Mastodon на Pethost в один клик
Свой сервер в федиверсе: посты, подписки и ответы по всему Mastodon и не только
Что произойдет
- Вы входите в Pethost или создаете аккаунт — с passkey, через GitHub или Google.
- Машины еще нет? Вы выбираете тариф, и мы готовим машину для вас. Ссылка ждет в вашем браузере, пока машина не будет готова.
- Окно «Новый проект» открывается на этом приложении. Вы заполняете то, что оно просит, и нажимаете «Создать проект»: Имя пользователя, Электронная почта, Пароль администратора.
- Через минуту-две приложение работает по своему адресу с HTTPS. Его секреты создаются случайно, а данные попадают в ночной бэкап.
- Это проект как любой другой: его compose.yaml, .env, логи и терминал — в панели, а ваш агент может его изменить, откатить или восстановить.
Первые шаги
Войдите с почтой и паролем, которые вы указали: вы владелец сервера, с тем именем пользователя, которое вы указали. Почта должна принимать письма: Mastodon проверяет её домен, иначе деплой не пройдёт. Имена вроде admin или root Mastodon резервирует. Регистрация закрыта; откройте её в Настройках, Администрирование, Настройки сервера. Mastodon не отправляет писем, пока SMTP_SERVER, SMTP_LOGIN, SMTP_PASSWORD и SMTP_FROM_ADDRESS не появятся в .env проекта и проект не перезапустится. Каждый аккаунт навсегда привязан к этому адресу, так что дайте проекту окончательный адрес до первых постов. Загруженные медиафайлы хранятся в /opt/mastodon/public/system.
Что запускается
Шаблон — это этот compose.yaml и переменные, которые он пишет в .env проекта. Pethost запускает файл так, как он написан.
# Mastodon's docker-compose.yml with a small Caddy in front, which gives the streaming
# API its path on the project's address, as Mastodon's nginx does.
x-env: &env
LOCAL_DOMAIN: ${HOST}
DB_HOST: db
DB_PORT: "5432"
DB_USER: mastodon
DB_NAME: mastodon
DB_PASS: ${DB_PASSWORD}
REDIS_HOST: redis
REDIS_PORT: "6379"
SECRET_KEY_BASE: ${SECRET_KEY_BASE}
ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY: ${AR_DETERMINISTIC_KEY}
ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT: ${AR_KEY_DERIVATION_SALT}
ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY: ${AR_PRIMARY_KEY}
VAPID_SEED: ${VAPID_SEED}
ES_ENABLED: "false"
WEB_CONCURRENCY: "1"
SMTP_SERVER: ${SMTP_SERVER:-}
SMTP_PORT: ${SMTP_PORT:-587}
SMTP_LOGIN: ${SMTP_LOGIN:-}
SMTP_PASSWORD: ${SMTP_PASSWORD:-}
SMTP_FROM_ADDRESS: ${SMTP_FROM_ADDRESS:-}
# Web push needs a VAPID key pair. Its private key is the 32 random bytes of VAPID_SEED,
# and the public key is derived from it, so web and sidekiq read the same pair and
# nothing is kept apart from .env.
x-vapid: &vapid |
eval "$$(ruby -ropenssl -rbase64 -e '
d = [ENV.fetch("VAPID_SEED")].pack("H*")
point = OpenSSL::PKey::EC::Group.new("prime256v1").generator.mul(OpenSSL::BN.new(d, 2))
puts "export VAPID_PRIVATE_KEY=#{Base64.urlsafe_encode64(d)}"
puts "export VAPID_PUBLIC_KEY=#{Base64.urlsafe_encode64(point.to_octet_string(:uncompressed))}"
')"
services:
proxy:
image: caddy:2.10-alpine
restart: unless-stopped
configs:
- source: caddy
target: /etc/caddy/Caddyfile
depends_on:
- web
- streaming
web:
image: ghcr.io/mastodon/mastodon:v4.7.3
restart: unless-stopped
environment:
<<: *env
ADMIN_USERNAME: ${ADMIN_USERNAME}
ADMIN_EMAIL: ${ADMIN_EMAIL}
ADMIN_PASSWORD: ${ADMIN_PASSWORD}
VAPID: *vapid
# Every start migrates the database and seeds what is missing; the first one also
# makes the owner from the username, email and password given. Registrations stay
# closed, Mastodon's default, so nobody else can sign up until the owner opens them.
command:
- sh
- -c
- |
set -e
eval "$$VAPID"
bundle exec rails db:prepare db:seed
bundle exec rails runner '
owner = UserRole.find_by!(name: "Owner")
unless User.exists?(role_id: owner.id)
password = ENV.fetch("ADMIN_PASSWORD")
user = User.create!(
email: ENV.fetch("ADMIN_EMAIL"),
password: password,
password_confirmation: password,
account: Account.new(username: ENV.fetch("ADMIN_USERNAME")),
role: owner,
confirmed_at: Time.now.utc,
agreement: true,
approved: true,
bypass_registration_checks: true
)
# Closed registrations leave a new user waiting for approval.
user.approve!
end
'
exec bundle exec puma -C config/puma.rb
volumes:
- system:/opt/mastodon/public/system
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
healthcheck:
test: ["CMD-SHELL", "curl -s --noproxy localhost localhost:3000/health | grep -q OK"]
interval: 10s
timeout: 5s
retries: 5
start_period: 300s
streaming:
image: ghcr.io/mastodon/mastodon-streaming:v4.7.3
restart: unless-stopped
environment: *env
command: node ./streaming/index.js
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
healthcheck:
test: ["CMD-SHELL", "curl -s --noproxy localhost localhost:4000/api/v1/streaming/health | grep -q OK"]
interval: 10s
timeout: 5s
retries: 5
sidekiq:
image: ghcr.io/mastodon/mastodon:v4.7.3
restart: unless-stopped
environment:
<<: *env
VAPID: *vapid
command:
- sh
- -c
- |
eval "$$VAPID"
exec bundle exec sidekiq
volumes:
- system:/opt/mastodon/public/system
depends_on:
web:
condition: service_healthy
db:
image: postgres:17
restart: unless-stopped
shm_size: 256mb
environment:
POSTGRES_USER: mastodon
POSTGRES_DB: mastodon
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- db:/var/lib/postgresql/data
healthcheck:
test: ["CMD", "pg_isready", "-U", "mastodon"]
interval: 5s
timeout: 5s
retries: 10
redis:
image: redis:7.4
restart: unless-stopped
volumes:
- redis:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 5s
retries: 10
configs:
# The machine's proxy is trusted for X-Forwarded-Proto, so Rails sees HTTPS.
caddy:
content: |
{
admin off
auto_https off
servers {
trusted_proxies static private_ranges
}
}
:8080 {
reverse_proxy /api/v1/streaming* streaming:4000
reverse_proxy web:3000
}
volumes:
system:
db:
redis: