简介

只部署服务,不讲原理。

本机配置:MacBook Pro M2 Max 32 GB

Mastodon 介绍

Mastodon 是一个自由、开源的去中心化的微博客平台,类似于 Twitter,但是使用分布式的架构,用户可以在不同的实例(服务器)之间自由迁移,并且可以互相关注和互相交流。Mastodon 的用户可以发布短文本、图片、视频、音频等内容,并且可以使用标签来组织和浏览内容。

Mastodon 的用户界面简洁、易用,支持自定义主题和语言,同时也支持多种客户端应用程序,包括 Web、Android、iOS 等。Mastodon 的消息是加密的,用户可以选择公开或私密地发布消息,同时也可以选择将消息限制在特定的用户或实例之间。

Mastodon 的去中心化架构使得其具有较高的安全性和可靠性,不易受到单点故障和攻击。同时,Mastodon 的开源性质也使得其具有较高的灵活性和可扩展性,开发者可以根据自己的需求进行定制和扩展。

总之,Mastodon 是一个自由、开源、去中心化的微博客平台,为用户提供了更加安全、可靠、灵活的社交体验。

(介绍来自ChatGPT3.5)

CleanShot 2023-07-13 at 10.06.36@2x

部署实践

搜索Mastodon你会发现有很多容器化部署的文章,可以参考借鉴。从完全部署运行后给我的感觉,只要认真看过官方文档,就能顺利的进行部署。

需要注意的细节,写最前面了

1,本地没有build镜像,使用的是官方镜像:

docker pull ghcr.io/mastodon/mastodon

2,networks与官方不同,因为我本地容器服务internal_、external_被占用了。另外traefik网络是为了与反向代理服务进行互通。不了解的可以参考以前文章

官方:

1networks:
2  - internal_network
3  - external_network

本地配置:

1networks:
2  - mastodon_networks
3  - traefik

3,一定要保证容器之间是互通的,否则找不到服务,会导致启动失败。

4,.env.production 配置文件在初始化安装的时候不需要引入!

5,创建网卡

1docker network create mastodon_networks
1,使用官方docker-compose进行配置拆分

官方docker-compose配置官方README 根据官方的配置文件共分为db、es、web、streaming、sidekiq5个服务融合在一起,不利于后期维护和服务更新。下面进行配置拆分。共拆分为4个服务。

1.1,PostgreSQL 配置

保存以下配置文件名为:docker-compose.postgresql.yml

 1version: '3'
 2services:
 3  postgresql:
 4    restart: always
 5    image: postgres:14-alpine
 6    shm_size: 256mb
 7    # 可视化连接使用
 8    ports:
 9      - 54322:5432
10    networks:
11      - mastodon_networks
12    healthcheck:
13      test: ['CMD', 'pg_isready', '-U', 'postgres']
14    volumes:
15      - ./postgres14:/var/lib/postgresql/data
16    environment:
17      POSTGRES_HOST_AUTH_METHOD: trust
18      # 设置个密码 可视化工具连接使用
19      POSTGRESQL_PASSWORD: bitnami1
20networks:
21  mastodon_networks:
22    external: true
1.2,Redis 配置

保存以下配置文件名为:docker-compose.redis.yml

 1version: '3'
 2services:
 3  redis:
 4    restart: always
 5    image: redis:7-alpine
 6    healthcheck:
 7      test: ['CMD', 'redis-cli', 'ping']
 8    volumes:
 9      - ./redis:/data
10    networks:
11      - mastodon_networks
12networks:
13  mastodon_networks:
14    external: true
15
1.3,Elasticsearch 配置

保存以下配置文件名为:docker-compose.elasticsearch.yml

 1version: '3'
 2
 3services:
 4  elasticsearch:
 5    restart: always
 6    image: docker.elastic.co/elasticsearch/elasticsearch:7.17.4
 7    environment:
 8      - "ES_JAVA_OPTS=-Xms512m -Xmx512m -Des.enforce.bootstrap.checks=true"
 9      - "xpack.license.self_generated.type=basic"
10      - "xpack.security.enabled=false"
11      - "xpack.watcher.enabled=false"
12      - "xpack.graph.enabled=false"
13      - "xpack.ml.enabled=false"
14      - "bootstrap.memory_lock=true"
15      - "cluster.name=es-mastodon"
16      - "discovery.type=single-node"
17      - "thread_pool.write.queue_size=1000"
18    networks:
19      - mastodon_networks
20    healthcheck:
21      test: ["CMD-SHELL", "curl --silent --fail localhost:9200/_cluster/health || exit 1"]
22    volumes:
23      - ./elasticsearch:/usr/share/elasticsearch/data
24    ulimits:
25      memlock:
26        soft: -1
27        hard: -1
28      nofile:
29        soft: 65536
30        hard: 65536
31    ports:
32      - '9200:9200'
33
34networks:
35  mastodon_networks:
36    external: true
1.4,服务web、streaming、sidekiq的配置

.env.production.sample 复制文件内容并保存为:.env.production

保存以下配置文件名为:docker-compose.start.yml

 1version: '3'
 2services:
 3  web:
 4    image: ghcr.io/mastodon/mastodon
 5    restart: always
 6    env_file: .env.production
 7    environment:
 8      RAILS_ENV: production
 9    command: bash -c "rm -f /mastodon/tmp/pids/server.pid; bundle exec rails s -p 3000"
10    healthcheck:
11      # prettier-ignore
12      test:
13        [
14          'CMD-SHELL',
15          'wget -q --spider --proxy=off localhost:3000/health || exit 1'
16        ]
17    volumes:
18      - ./public/system:/mastodon/public/system
19    networks:
20      - mastodon_networks
21      - traefik
22  streaming:
23    image: ghcr.io/mastodon/mastodon
24    restart: always
25    env_file: .env.production
26    command: node ./streaming
27    environment:
28      - "NODE_ENV=production"
29    healthcheck:
30      # prettier-ignore
31      test:
32        [
33          'CMD-SHELL',
34          'wget -q --spider --proxy=off localhost:4000/api/v1/streaming/health || exit 1'
35        ]
36    networks:
37      - mastodon_networks
38      - traefik
39  sidekiq:
40    image: ghcr.io/mastodon/mastodon
41    restart: always
42    env_file: .env.production
43    environment:
44      - "RAILS_ENV=production"
45    command: bundle exec sidekiq
46    networks:
47      - mastodon_networks
48      - traefik
49    volumes:
50      - ./public/system:/mastodon/public/system
51    healthcheck:
52      test: [ 'CMD-SHELL', "ps aux | grep '[s]idekiq 6' || false" ]
53
54networks:
55  mastodon_networks:
56    external: true
57  traefik:
58    external: true
1.5,配置前端代理服务

NGINX配置参考官方配置nginx-configuration,删除了一下其他配置。修改了client_max_body_size为100,解决上传大图片返回413错误。(自行调整)

保存以下配置文件名为:docker-compose.index.yml

 1version: "3.6"
 2services:
 3  mastodon-halobug:
 4    image: nginx:1.21.4-alpine
 5    restart: always
 6    expose:
 7      - 80
 8    volumes:
 9      - /etc/localtime:/etc/localtime:ro
10      - /etc/timezone:/etc/timezone:ro
11      - ./nginx.index.conf:/etc/nginx/conf.d/default.conf
12    networks:
13      - traefik
14      - mastodon_networks
15    labels:
16      - "traefik.enable=true"
17      - "traefik.docker.network=traefik"
18      - "traefik.http.routers.mastodon-halobug.entrypoints=https"
19      - "traefik.http.routers.mastodon-halobug.tls=true"
20      - "traefik.http.routers.mastodon-halobug.rule=Host(`chat.halobug.cn`)"
21      - "traefik.http.services.mastodon-halobug-backend.loadbalancer.server.scheme=http"
22      - "traefik.http.services.mastodon-halobug-backend.loadbalancer.server.port=80"
23    logging:
24      driver: "json-file"
25      options:
26        max-size: "1m"
27networks:
28  mastodon_networks:
29    external: true
30  traefik:
31    external: true

保存以下配置文件名为:nginx.index.conf

 1map $http_upgrade $connection_upgrade {
 2  default upgrade;
 3  ''      close;
 4}
 5server {
 6    listen 80;
 7    server_name default_server;
 8     keepalive_timeout    70;
 9    sendfile             on;
10    client_max_body_size 100m;
11
12    root /home/mastodon/live/public;
13
14    gzip on;
15    gzip_disable "msie6";
16    gzip_vary on;
17    gzip_proxied any;
18    gzip_comp_level 6;
19    gzip_buffers 16 8k;
20    gzip_http_version 1.1;
21    gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
22
23    add_header Strict-Transport-Security "max-age=31536000";
24
25    location / {
26        try_files $uri @proxy;
27    }
28
29    location ~ ^/(emoji|packs|system/accounts/avatars|system/media_attachments/files) {
30        add_header Cache-Control "public, max-age=31536000, immutable";
31        try_files $uri @proxy;
32    }
33
34    location /sw.js {
35        add_header Cache-Control "public, max-age=0";
36        try_files $uri @proxy;
37    }
38
39    location @proxy {
40        proxy_set_header Host $host;
41        proxy_set_header X-Real-IP $remote_addr;
42        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
43        proxy_set_header X-Forwarded-Proto "https";
44        proxy_set_header Proxy "";
45        proxy_pass_header Server;
46
47        proxy_pass http://web:3000;
48        proxy_buffering on;
49        proxy_redirect off;
50        proxy_http_version 1.1;
51        proxy_set_header Upgrade $http_upgrade;
52        proxy_set_header Connection $connection_upgrade;
53
54        tcp_nodelay on;
55    }
56
57    location /api/v1/streaming {
58        proxy_set_header Host $host;
59        proxy_set_header X-Real-IP $remote_addr;
60        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
61        proxy_set_header X-Forwarded-Proto "https";
62        proxy_set_header Proxy "";
63
64        proxy_pass http://streaming:4000;
65        proxy_buffering off;
66        proxy_redirect off;
67        proxy_http_version 1.1;
68        proxy_set_header Upgrade $http_upgrade;
69        proxy_set_header Connection $connection_upgrade;
70
71        tcp_nodelay on;
72    }
73}
2,搭建文件存储服务
2.1,运行Minio

保存以下配置文件名为:docker-compose.minio.yml

 1version: "3"
 2
 3services:
 4
 5  mastodon-minio-nginx:
 6    image: nginx:1.21.4-alpine
 7    volumes:
 8       - ./nginx.minio.conf:/etc/nginx/conf.d/default.conf:ro
 9    expose:
10      - 80
11    environment:
12      - NGINX_HOST=localhost
13      - NGINX_PORT=80
14    networks:
15      - traefik
16      - mastodon_networks
17    labels:
18      - "traefik.enable=true"
19      - "traefik.docker.network=traefik"
20      - "traefik.http.routers.mastodon-oss-http.entrypoints=http"
21      - "traefik.http.routers.mastodon-oss-http.rule=Host(`oss.halobug.cn`)"
22      - "traefik.http.routers.mastodon-oss-https.entrypoints=https"
23      - "traefik.http.routers.mastodon-oss-https.tls=true"
24      - "traefik.http.routers.mastodon-oss-https.rule=Host(`oss.halobug.cn`)"
25      - "traefik.http.services.mastodon-oss-backend.loadbalancer.server.scheme=http"
26      - "traefik.http.services.mastodon-oss-backend.loadbalancer.server.port=80"
27    depends_on:
28      - minio
29  minio:
30    image: minio/minio:RELEASE.2022-01-08T03-11-54Z
31    volumes:
32      - ./minio/data:/data:z
33    command: minio server /data --address 0.0.0.0:80 --listeners 1  --console-address 0.0.0.0:9001
34    environment:
35      MINIO_ROOT_USER: umf3V1C3Hu5TzCDDqIXFbDDviYGhV627
36      MINIO_ROOT_PASSWORD: OqIwA1GJADWgCf5yvlRTKTJ6bTYAhaO9exqX5lo3GlOlLfVcIbn4v2CsuamB
37      MINIO_REGION_NAME: cn-homelab-1
38      MINIO_BROWSER: on
39      MINIO_BROWSER_REDIRECT_URL: https://mastodon-s3.halobug.cn
40      MINIO_PROMETHEUS_AUTH_TYPE: public
41    restart: always
42    ports:
43      - 9001:9001
44    expose:
45      - 80
46    networks:
47      - traefik
48      - mastodon_networks
49    labels:
50      - "traefik.enable=true"
51      - "traefik.docker.network=traefik"
52      - "traefik.http.middlewares.minio-gzip.compress=true"
53      - "traefik.http.routers.minio-admin.middlewares=minio-gzip"
54      - "traefik.http.routers.minio-admin.entrypoints=https"
55      - "traefik.http.routers.minio-admin.tls=true"
56      - "traefik.http.routers.minio-admin.rule=Host(`mastodon-s3.halobug.cn`)"
57      - "traefik.http.routers.minio-admin.service=minio-admin-backend"
58      - "traefik.http.services.minio-admin-backend.loadbalancer.server.scheme=http"
59      - "traefik.http.services.minio-admin-backend.loadbalancer.server.port=80"
60    healthcheck:
61      test: ["CMD", "curl", "-f", "http://localhost:80/minio/health/live"]
62      interval: 3s
63      retries: 12
64    logging:
65      driver: "json-file"
66      options:
67        max-size: "10m"
68networks:
69  traefik:
70    external: true
71  mastodon_networks:
72    external: true

保存以下配置文件名为:nginx.minio.conf

 1server {
 2    listen 80;
 3    server_name localhost;
 4
 5    keepalive_timeout 70;
 6    sendfile on;
 7    client_max_body_size 80m;
 8
 9    location / {
10        proxy_set_header X-Real-IP $remote_addr;
11        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
12        proxy_set_header X-Forwarded-Proto $scheme;
13        proxy_set_header Host $http_host;
14
15        proxy_connect_timeout 300;
16        proxy_http_version 1.1;
17        proxy_set_header Connection "";
18        chunked_transfer_encoding off;
19
20        proxy_pass http://minio/mastodon/;
21    }
22
23    location /health {
24        access_log off;
25        return 200 "ok";
26    }
27}

运行minio

1 docker-compose -f docker-compose.minio.yml up -d

CleanShot 2023-07-13 at 13.13.26@2x

2.2,初始化Minio

保存以下配置文件名为:docker-compose.minio.init.yml

 1version: "3"
 2services:
 3
 4  minio-client:
 5    image: minio/mc:RELEASE.2022-01-07T06-01-38Z
 6    entrypoint: >
 7      /bin/sh -c "
 8      /usr/bin/mc config host rm local;
 9      /usr/bin/mc config host add --quiet --api s3v4 local http://minio umf3V1C3Hu5TzCDDqIXFbDDviYGhV627 OqIwA1GJADWgCf5yvlRTKTJ6bTYAhaO9exqX5lo3GlOlLfVcIbn4v2CsuamB;
10      /usr/bin/mc mb --quiet local/mastodon/;
11      /usr/bin/mc policy set public local/mastodon;
12      "      
13    networks:
14      - traefik
15
16networks:
17  traefik:
18    external: true

运行命令(运行一次即可)

1 docker-compose -f docker-compose.minio.init.yml up

CleanShot 2023-07-13 at 13.26.50@2x

本地绑定hosts

1127.0.0.1 mastodon-s3.halobug.cn oss.halobug.cn

浏览器访问 http://127.0.0.1:9001

CleanShot 2023-07-13 at 13.22.31@2x

初始化完成后查看Buckets

CleanShot 2023-07-13 at 14.26.45@2x

到此存储服务部署完成,下面开始启动基础服务。

所有配置文件

CleanShot 2023-07-13 at 14.54.28@2x

3,启动基础服务
3.1,运行PostgreSQL
1docker-compose -f docker-compose.postgresql.yml up -d
3.2,运行Redis
1docker-compose -f docker-compose.redis.yml up -d
3.3,运行Elasticsearch
1docker-compose -f docker-compose.elasticsearch.yml up -d

全部使用官方镜像,启动成功后如下图所示:

CleanShot 2023-07-13 at 11.37.17

4,安装Mastodon
4.1,容器内执行安装命令

上一步已经说了,安装的注意事项。再次提醒心急的同学们。

1.env.production 配置文件在初始化安装的时候不需要引入

CleanShot 2023-07-13 at 11.56.13@2x

执行安装命令:

1docker-compose -f docker-compose.start.yml run --rm web bundle exec rake mastodon:setup

CleanShot 2023-07-13 at 11.58.44@2x

按照安装引导进行配置

CleanShot 2023-07-13 at 12.04.32@2x

安装完成后的配置

CleanShot 2023-07-13 at 12.08.33@2x

 1# Generated with mastodon:setup on 2023-07-13 04:02:06 UTC
 2
 3# Some variables in this file will be interpreted differently whether you are
 4# using docker-compose or not.
 5
 6LOCAL_DOMAIN=chat.halobug.cn
 7SINGLE_USER_MODE=false
 8SECRET_KEY_BASE=d2f61bffbf601042a51bbbae7732ebb93a5803ac40713e3275220aa5894d1132bd4e0870c4fa3f17f99f5d7e06e7c83a46ec0f31b31c60b38242d8d07f042b96
 9OTP_SECRET=cecbae5d4595c57299b3d30eabc21f8c16c54d508a66547bbff107ad6d029a9129c252067aae6b9b725c7ce547a68b65a1eff5fc34efb112a35089fab193820d
10VAPID_PRIVATE_KEY=9G4BjizL7_qyW8IwDhF-ILX_fdURffERFK8HT7sGrOs=
11VAPID_PUBLIC_KEY=BIuyba_wWuguaTSZMqiFPOd6CzIv3wHKwdiD38oeOm5_IYfFIC0F3YOK7Muh7XO2EwLf3Og0ToprvQ-lejhsEpk=
12DB_HOST=postgresql
13DB_PORT=5432
14DB_NAME=postgres
15DB_USER=postgres
16DB_PASS=bitnami1
17REDIS_HOST=redis
18REDIS_PORT=6379
19REDIS_PASSWORD=
20SMTP_SERVER=smtp.mailgun.org
21SMTP_PORT=587
22SMTP_LOGIN=
23SMTP_PASSWORD=
24SMTP_AUTH_METHOD=plain
25SMTP_OPENSSL_VERIFY_MODE=none
26SMTP_ENABLE_STARTTLS=auto
27SMTP_FROM_ADDRESS=Mastodon <notifications@chat.halobug.cn>

之后你会发现运行有个异常,因为docker-compose.start.yml文件里还有streaming、sidekiq这两个服务。并且到此使用的还是官方默认的配置文件、找不到对应的基础服务造成的。按照输出的配置重新修改即可。

CleanShot 2023-07-13 at 12.10.46@2x

4.2,将安装后配置参数值,复制至官方配置文件中

需要注意的是,安装引导没有Elasticsearch的指导。在配置文件中加上即可,ES_USER、ES_PASS设为空。

SMTP配置:我有阿里云服务所以直接配置了。(你也可以自己申请SMTP,自己搜索吧)

4.3,S3存储配置
1S3_ENABLED=true
2S3_PROTOCOL=https
3S3_BUCKET=mastodon
4S3_REGION=cn-homelab-1
5S3_ALIAS_HOST=oss.halobug.cn
6S3_ENDPOINT=https://mastodon-s3.halobug.cn
7AWS_ACCESS_KEY_ID=umf3V1C3Hu5TzCDDqIXFbDDviYGhV627
8AWS_SECRET_ACCESS_KEY=OqIwA1GJADWgCf5yvlRTKTJ6bTYAhaO9exqX5lo3GlOlLfVcIbn4v2CsuamB

因为是单机部署,容器间通讯用无法使用https,所以在docker-compose.start.yml中web、streaming、sidekiq 配置中增加extra_hosts。192.168.12.89 为局域网IP。

1    extra_hosts:
2      - "mastodon-s3.halobug.cn:192.168.12.89"

配置参考图:

CleanShot 2023-07-13 at 14.15.09@2x

4.4,将env_file的注释“打开”

4.1注释了配置文件,现在重新“打开” CleanShot 2023-07-13 at 12.29.09@2x

之后进入启动服务的流程

5,启动服务
5.1,运行Mastodon

启动命令:

1docker-compose -f docker-compose.start.yml up -d

查看日志:

1docker-compose -f docker-compose.start.yml logs -f

启动后如图所示

CleanShot 2023-07-13 at 12.31.04@2x

正常运行后,还差最后一步,即可对外提供服务。

5.2,启动 docker-compose.index.yml

自行配置https,可参考以前文章。

启动命令:

1docker-compose -f docker-compose.index.yml up -d

CleanShot 2023-07-13 at 12.38.13@2x

本地绑定hosts。

1127.0.0.1 chat.halobug.cn
6,注册使用
6.1,访问

浏览器访问 https://chat.halobug.cn

CleanShot 2023-07-13 at 12.41.26@2x

6.2,注册账号进行测试

CleanShot 2023-07-13 at 13.50.07@2x

6.3,邮件验证

过不了多久就收到一封邮件进行确认。

CleanShot 2023-07-13 at 13.49.16@2x

6.4,点开邮件中的连接,验证即可。成功后的页面

CleanShot 2023-07-13 at 13.51.43@2x

6.5,发布你的第一条动态吧。你好,世界!

CleanShot 2023-07-13 at 13.54.10@2x

CleanShot 2023-07-13 at 14.28.24@2x

到此服务搭建成功。

参考3.4版本的文章