部署Mastodon服务器

可能存在的问题

1. 使用cloudflare warp进行内网穿透可能无法订阅中继站
2. S3_ALIAS_HOST需要和LOCAL_DOMAIN使用相同域名,将S3资源定义为Mastodon域名下的路径,并做转发
3. S3设置可能不是最优设置,Just works
4. 注释docker-compose.yml的build提高部署效率

提前准备

  • 支持smtp协议的Email账户、密码(应用码)
  • 域名
  • 服务器
  • S3 (可选)

根据配置文件部署

  1. 下载mastodon配置文件和docker-compose.yml

    1
    2
    git clone https://github.com/mastodon/mastodon.git
    git fetch && git checkout v4.2.12
  2. 根据配置文件(.env.production.sample)要求填写信息:

    • 额外添加 SINGLE_USER_MODE=true 设置单用户模式
    • S3_ALIAS_HOST需要和LOCAL_DOMAIN使用相同域名,将S3资源定义为Mastodon域名下的路径,例如:
      1
      2
      LOCAL_DOMAIN=mastodon.example.com
      S3_ALIAS_HOST=mastodon.example.com/s3
    • VAPID生成
      1
      docker compose run --rm web rake mastodon:webpush:generate_vapid_key
    • SECRET_KEY_BASE, OTP_SECRET生成
      1
      docker compose run --rm -- web bundle exec rake secret
    • ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY \ ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT \ ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY
      1
      docker compose run --rm -- web bundle exec rails db:encryption:init
  3. 初始化数据库

    1. 初始化Postgres

      1
      2
      3
      4
      docker run --rm --name postgres \
      -v $PWD/postgres14:/var/lib/postgresql/data \
      -e POSTGRES_PASSWORD="098f6bcd4621d37" \
      -d postgres:14-alpine
    2. 进入Postgres 控制台

      1
      docker exec -it postgres psql -U postgres
    3. 创建用户和数据库

      1
      2
      3
      4
      5
      CREATE USER pg_mastodon WITH PASSWORD 'pg_passowrd' CREATEDB;
      CREATE DATABASE db_mastodon;
      \c db_mastodon;
      CREATE extension pg_stat_statements;
      exit
    4. 关闭数据库

      1
      docker stop postgres
  4. S3

    1. 参考Cloudflare说明开启S3_BUCKET,记录信息:
    • BUCKET_NAME
      
    • ACCESS_KEY_ID
      
    • SECRET_ACCESS_KEY
      
    • S3_ENDPOINT
      
    1. 设置CROS策略:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      [
      {
      "AllowedOrigins": [
      "*"
      ],
      "AllowedMethods": [
      "GET",
      "HEAD"
      ]
      }
      ]
    2. 在控制台设置自定义域

    s3.example.com

    1. 设置如下
      1
      2
      3
      4
      5
      6
      7
      S3_ENABLED=true
      S3_BUCKET=BUCKET_NAME
      S3_ENDPOINT=https://your_id.r2.cloudflarestorage.com/mastodon
      AWS_ACCESS_KEY_ID={ACCESS_KEY_ID}
      AWS_SECRET_ACCESS_KEY={SECRET_ACCESS_KEY}
      S3_ALIAS_HOST=mastodon.example.com/s3
      S3_PERMISSION = "private"
  5. 生成容器

    1
    docker compose run --rm -v $(pwd)/.env.production:/opt/mastodon/.env.production web bundle exec rake db:setup
  6. 配置权限

    1
    2
    chown -R 70:70 postgres14
    chown -R 991:991 public
  7. 执行

    1
    docker compose up -d
  8. 生成管理员用户名和密码

    1
    2
    docker exec mastodon-web-1 tootctl accounts create "username" --email "user@email.com" --confirmed --role Owner
    docker exec mastodon-web-1 tootctl accounts modify --approve "username"

交互式部署

  1. 初始化Postgres

    1
    2
    3
    4
    docker run --rm --name postgres \
    -v $PWD/postgres14:/var/lib/postgresql/data \
    -e POSTGRES_PASSWORD="098f6bcd4621d37" \
    -d postgres:14-alpine
  2. 进入Postgres 控制台

    1
    docker exec -it postgres psql -U postgres
  3. 创建用户和数据库

    1
    2
    3
    4
    5
    CREATE USER pg_mastodon WITH PASSWORD 'pg_passowrd' CREATEDB;
    CREATE DATABASE db_mastodon;
    \c db_mastodon;
    CREATE extension pg_stat_statements;
    exit
  4. 关闭数据库

    1
    docker stop postgres
  5. 根据安装向导填写信息

    1
    2
    wget https://raw.githubusercontent.com/mastodon/mastodon/main/docker-compose.yml
    docker compose run --rm web bundle exec rake mastodon:setup
  6. 配置权限

    1
    2
    chown -R 70:70 postgres14
    chown -R 991:991 public
  7. 执行

    1
    docker compose up -d

Caddy2 反向代理

  • Mastodon仅支持引用与其相同域名下的资源。为了能够在Mastodon中引用存储在S3上的资源,通过设置S3_ALIAS_HOST将S3资源定义为Mastodon域名下的路径。这需要使用URL重写技术,以便请求能够被转发到S3服务器。
  • 注意将root * /home/user/mastodon/public修改为合适的位置。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    mastodon.powernut.rocks {
    @local {
    file
    not path /
    }

    log {
    output file /var/log/caddy/mastodon.log
    }

    @local_media {
    path_regexp /system/(.*)
    }
    @streaming {
    path /api/v1/streaming/*
    }
    @cache_control {
    path_regexp ^/(emoji|packs|/system/accounts/avatars|/system/media_attachments/files)
    }

    root * /home/user/mastodon/public

    encode zstd gzip

    handle_errors {
    rewrite 500.html
    file_server
    }

    header {
    Strict-Transport-Security "max-age=31536000"
    }
    header /sw.js Cache-Control "public, max-age=0"
    header @cache_control Cache-Control "public, max-age=31536000, immutable"

    handle @local {
    file_server
    }

    # If you've been migrated media from local to object storage, this navigate old URL to new one.
    # redir @local_media https://yourobjectstorage.example.com/{http.regexp.1} permanent

    reverse_proxy @streaming {
    to http://127.0.0.1:4000

    transport http {
    keepalive 5s
    keepalive_idle_conns 10
    }
    }

    reverse_proxy {
    to http://127.0.0.1:3000

    header_up X-Forwarded-Port 443
    header_up X-Forwarded-Proto https

    transport http {
    keepalive 5s
    keepalive_idle_conns 10
    }
    }

    handle_path /s3/* {
    rewrite * /mastodon-buckets_name{path}
    reverse_proxy https://s3.server.com {
    header_up Host {http.reverse_proxy.upstream.hostport}
    }
    }
    }