Polski
Zacznij
← Wszystkie szablony

Wdróż aplikację Mastodon na Pethost jednym kliknięciem

Twój własny serwer w fediwersum: wpisy, obserwowanie i odpowiedzi poza samym Mastodonem

Co się dzieje

  1. Logujesz się do Pethost albo zakładasz konto, kluczem dostępu, przez GitHub albo Google.
  2. Nie masz jeszcze maszyny? Wybierasz plan, a my ją dla ciebie przygotowujemy. Link czeka w twojej przeglądarce, aż będzie gotowa.
  3. Okno „Nowy projekt” otwiera się na tej aplikacji. Wypełniasz to, o co prosi, i klikasz „Utwórz projekt”: Nazwa użytkownika, E-mail, Hasło administratora.
  4. Za minutę czy dwie aplikacja działa pod własnym adresem z HTTPS. Jej sekrety są tworzone losowo, a dane trafiają do nocnego backupu.
  5. To projekt jak każdy inny: jego compose.yaml, .env, logi i terminal są w panelu, a twój agent może go zmienić, cofnąć do wcześniejszej wersji albo przywrócić.

Pierwsze kroki

Zaloguj się e-mailem i hasłem, które podano: jesteś właścicielem serwera, z nazwą użytkownika, którą podano. E-mail musi przyjmować pocztę: Mastodon sprawdza jego domenę, a bez tego wdrożenie się nie uda. Nazwy takie jak admin czy root Mastodon rezerwuje. Rejestracja jest zamknięta; otwórz ją w Ustawienia, Administracja, Ustawienia serwera. Mastodon nie wysyła e-maili, dopóki SMTP_SERVER, SMTP_LOGIN, SMTP_PASSWORD i SMTP_FROM_ADDRESS nie trafią do pliku .env projektu, a projekt się nie zrestartuje. Każde konto jest na zawsze związane z tym adresem, więc nadaj projektowi docelowy adres, zanim cokolwiek opublikujesz. Wgrane media zostają w /opt/mastodon/public/system.

Co uruchamia

Szablon to ten compose.yaml i zmienne, które zapisuje do .env projektu. Pethost uruchamia plik dokładnie tak, jak jest napisany.

# 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: