Files

14 KiB
Raw Permalink Blame History

WALKTHROUGH — GoToSocial (капитанский журнал)

Хронология реализации. Цель — воспроизводимость с нуля.

2026-09-06 — Инициализация проекта

Задача

Развернуть GoToSocial (федiverse-нода ActivityPub) в Docker: /opt/gotosocial, OpenSpec workflow, первое change на развёртывание, git (gitverse истина + gitea зеркало), бэкап на Яндекс.Диск, мониторинг — post-MVP.

Решения пользователя (ответы на вопросы)

  • БД: SQLite
  • Схема: split-domain (host=social.dedinit.ru, account-domain=dedinit.ru), доступ к созданию файлов на apex есть
  • Имя инстанса: dedinit.ru; admin: estorozhenko; название сервера: dedinit(); описание: «Нода для обычных людей»; email: kpa39l@yandex.ru
  • SMTP: smtp.jino.ru:587 STARTTLS, ящик social@dedinit.ru (пароль в .env)
  • Бэкап: SQLite consistent + медиа
  • Мониторинг бэкапов/дашборд Grafana/импорт из Telegram — post-MVP
  • Метрики/логи: отдельный job (не включать в общий)
  • vps02 — только прокси, сервис на bigbox
  • Git: последний стабильный тег с фиксацией, ручное обновление
  • Секреты в .env, в git исключён
  • Первый коммит — сразу с начальными изменениями (не ждать готового сервиса)

Исследование

Инфраструктура (проверено)

  • bigbox (10.8.0.2 через WG): сервисы в /opt/, стек мониторинга (Prometheus :9090, Grafana :3001, Loki :3100, node_exporter + textfile /var/lib/prometheus/node-exporter/)
  • vps02 87.242.100.206: Caddy 2 (контейнер caddy:alpine, host net), слушает 80/443, паттерн домен { reverse_proxy 10.8.0.2:<port> }
  • SSH vps02: ssh -i /mnt/yandex-disk/.ssh_box/cloudruVPS estorozhenko@87.242.100.206 (sudo работает); root/другие ключи НЕ подходят
  • Яндекс.Диск: mount /mnt/yandex-disk, бэкапы в /mnt/yandex-disk/backup/-backups/
  • DNS: social.dedinit.ru A → 87.242.100.206 (создан пользователем), apex dedinit.ru → 81.177.135.38 (Jino)

OpenSpec workflow

cd /opt/gotosocial
openspec init --tools hermes --force --no-animation   # CLI 1.12.0, бинарь /opt/hermes/.hermes/node/bin/openspec
openspec new change deploy-gotosocial
  • config.yaml (context + rules) — инфра-специфичный
  • proposal.md, specs/gotosocial-deploy/spec.md + specs/gotosocial-backup/spec.md, design.md, tasks.md
  • Питфол: OpenSpec требует #### Scenario: блоки (GIVEN/WHEN/THEN) ВНУТРИ каждой requirement — просто Verification-блок не проходит validate. Исправлено, openspec validate deploy-gotosocial → valid.

Рабочие файлы

  • docker-compose.yml: image superseriousbusiness/gotosocial:v0.22.1 (фикс. тег), container_name gotosocial, user 1000:1000, restart unless-stopped, env OTEL_METRICS_*, env_file .env, ports 8080:8080, volumes ./data:/gotosocial/storage + ./config.yaml:/gotosocial/config.yaml:ro, network gotosocial 172.29.0.0/16
  • config.yaml: host social.dedinit.ru, account-domain dedinit.ru, protocol https, port 8080, trusted-proxies [127.0.0.1/32, ::1, 172.29.0.1/16], log json, db-type sqlite, db-address /gotosocial/storage/sqlite.db, storage-local-base-path /gotosocial/storage, SMTP smtp.jino.ru:587 (пароль пустой в config — берётся из .env? TODO: проверить, как GtS читает пароль из env, когда в config.yaml пусто), metrics-enabled true, instance-title dedinit(), instance-description «Нода для обычных людей», instance-contact-email kpa39l@yandex.ru
  • .env: GTS_SMTP_PASSWORD='fF@4guOf9spE2#8$'
  • backup.sh: VACUUM INTO → tar.gz (sqlite+storage) + отдельный .env-архив; копия /mnt/yandex-disk/backup/gotosocial-backups/; ротация локально 7д, ЯД 30д; mountpoint-проверка ЯД, exit 1 при ошибке
  • README.md, .gitignore (.env, data/, backups/, refs/, openspec/changes/archive/)

Git

cd /opt/gotosocial
git init -b main && git add -A
git -c user.name=estorozhenko -c user.email=kpa39l@yandex.ru commit -m "openspec: change deploy-gotosocial — развертывание GoToSocial (compose+config+backup+docs)"
# d385d8b

Создание репозитория gitverse (ВАЖНО — питфолы)

  • SSH-ключ gitverse работает: ssh -i /mnt/yandex-disk/.ssh_box/gitverse git@gitverse.ru → «Hi kpa39l!»
  • push-to-create НЕ включён для пользователей: «Push to create is not enabled»
  • Токен из obsidian vault (Gitverse mirror token.md, 40 hex) НЕ работает для API gitverse (400 на всё) — это токен gitea-зеркала
  • Правильный способ — скилл git-forge-management + reference gitverse-api.md:
    • Токен: source /opt/hermes/.hermes/secrets/git-tokens.env → GITVERSE_PAT, GITVERSE_API, GITVERSE_LOGIN=kpa39l
    • Accept header ОБЯЗАТЕЛЕН: application/vnd.gitverse.object+json;version=1 (без него 400)
curl -s -X POST "${GITVERSE_API}/user/repos" \
  -H "Authorization: Bearer ${GITVERSE_PAT}" \
  -H "Accept: application/vnd.gitverse.object+json;version=1" \
  -H "Content-Type: application/json" \
  -d '{"name":"gotosocial","description":"...","private":false,"auto_init":false}'
# HTTP 201, id 327796, full_name kpa39l/gotosocial

Push

  • Логин аккаунта gitverse = kpa39l (не estorozhenko!)
git remote add origin "https://kpa39l:${GITVERSE_PAT}@gitverse.ru/kpa39l/gotosocial.git"
git push -u origin main
  • Питфол: токен остался зашит в .git/config — убрано: git remote set-url origin https://kpa39l@gitverse.ru/kpa39l/gotosocial.git (creds из git-tokens.env/credential helper)

Gitea pull-mirror

source /opt/hermes/.hermes/secrets/git-tokens.env
curl -s -X POST "${GITEA_API}/repos/migrate" \
  -H "Authorization: token ${GITEA_TOKEN}" -H "Content-Type: application/json" \
  -d "{\"clone_addr\":\"https://oauth2:${GITVERSE_PAT}@gitverse.ru/kpa39l/gotosocial.git\",\"repo_name\":\"gotosocial\",\"repo_owner\":\"estorozhenko\",\"service\":\"git\",\"mirror\":true,\"mirror_interval\":\"8h\"}"
# HTTP 201, mirror=true; затем POST /repos/estorozhenko/gotosocial/mirror-sync → 200
  • Питфол: migrate с ssh:// НЕ работает (422 protocol not allowed) — только HTTPS + oauth2:PAT (проверено ранее, см. reference gitea-pull-mirror-gitverse.md)

Команды развёртывания (следующий шаг)

cd /opt/gotosocial && docker compose up -d
docker compose exec gotosocial gotosocial admin account create \
  --username estorozhenko --email kpa39l@yandex.ru \
  --password '<пароль>' --confirmation
docker compose exec gotosocial gotosocial admin account promote --username estorozhenko

Caddy vps02: блок social.dedinit.ru { reverse_proxy 10.8.0.2:8080 }, docker exec caddy caddy reload --config /etc/caddy/Caddyfile

Открытые вопросы / риски

  • Как GtS читает SMTP-пароль: config.yaml smtp-password: "" + .env GTS_SMTP_PASSWORD — проверить при первом запуске, что письма уходят
  • Пароль админа estorozhenko — нужен от пользователя
  • Доступ к vps02 для правки Caddyfile — нужен (SSH estorozhenko@87.242.100.206 + cloudruVPS ключ)
  • .well-known редиректы на apex (Jino) — подготовить правила

2026-09-13 — Почта: пустой From → спам (причина и фикс)

Симптом

  • Письма GoToSocial (подтверждение регистрации и т.п.) уходили на внешние ящики (Яндекс) в СПАМ.
  • Заголовки: From: <> (пустой) — письмо без отправителя.
  • X-Yandex-Spam: 4 (pessimistic).

Диагностика

  1. SMTP Jino напрямую (python smtplib): логин social@dedinit.ru OK, RCPT kpa39l@ya.ru OK, DATA → 250 Ok: queued. SMTP-стек рабочий.
  2. DNS dedinit.ru: SPF и DMARC ОТСУТСТВОВАЛИ; DKIM default._domainkey был.
  3. Исходники GtS (/tmp/gts-src, v0.22.1), state.go:100-101: флаг --smtp-from → env GTS_SMTP_FROM.
  4. В docker-compose.yml стоял неверный env: GTS_SMTP_FROM_ADDRESS (такого ключа нет → From пустой).

Фикс

# docker-compose.yml: GTS_SMTP_FROM_ADDRESS: "..." → GTS_SMTP_FROM: "social@dedinit.ru"
cd /opt/gotosocial && docker compose up -d --force-recreate gotosocial

Питфол — systemd1 D-Bus завис

  • docker compose up завис: systemd1 D-Bus таймаут 25s, контейнер остался Created.
  • Обход: /etc/docker/daemon.json → "native.cgroupdriver": "cgroupfs", systemctl restart docker (вручную, минуя systemd1).
  • Риск: после перезагрузки bigbox dockerd может не подняться сам (systemd1 фризит). Проверить при следующем ребуте. (Другой вариант — перезапуск systemd как PID 1; не делали.)

Проверка

Openspec (posthoc)

  • change fix-smtp-from-address → spec gotosocial/smtp-email (3 MUST: корректные env-ключи SMTP, непустой From, SPF/DMARC), archive.
  • Коммит 1cee142: docker-compose.yml + STATUS.md + openspec.

2026-09-19 — Управление проектом + SPF/DKIM + мониторинг

Жёсткое правило openspec (AGENTS.md)

  • По требованию пользователя в проект добавлено правило: все изменения — через OpenSpec (propose → apply-change → archive); исключение — явная команда владельца с bypass-openspec: в коммите.
  • Носители: AGENTS.md (для агентов), openspec/config.yaml (context — инжектится во все артефакты), README.md (для людей), spec gotosocial/project-governance (3 требования со Scenario).
  • change enforce-openspec-workflow → archive. Коммит 568335a.

SPF/DKIM (Jino, панель домена)

  • SPF: v=spf1 redirect=_spf.jino.ru (хост dedinit.ru, IN TXT) — включено пользователем 19.09.
  • DKIM: v=DKIM1; t=s; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A… (хост dkim._domainkey.dedinit.ru, IN TXT) — включено.
  • DMARC: не подтверждён (ранее рекомендовано v=DMARC1; p=none; rua=mailto:admin@dedinit.ru). Открытая задача.

Мониторинг :9464 (дашборд Grafana)

  • Job gotosocial в /opt/monitoring/prometheus.yml уже был (127.0.0.1:9464/metrics, relabel instance=bigbox:9464); VictoriaMetrics (127.0.0.1:9090) тянет — проверено /api/v1/series?match[]=gotosocial_instance_total_users.
  • Создан дашборд /opt/monitoring/grafana/dashboards/gotosocial/gotosocial.json (генератор scripts/gen_gotosocial_dash.py, 20 панелей: Доступность/Инстанс/Воркеры/HTTP/SQL/Процесс; uid gotosocial-main).
  • dashboards.yml: добавлен провайдер gotosocial-dashboards (folder gotosocial). Заодно починен дефект: провайдер garage-dashboards смотрел на ВЕСЬ /var/lib/grafana/dashboards, дублируя nodes/vinogorod/vesti → Grafana блокировала запись всех новых дашбордов («the same UID is used more than once» + «no database write permissions because of duplicates»). Сужен до /var/lib/grafana/dashboards/garage-cluster.json; docker compose restart grafana.
  • Проверка: gotosocial-main в grafana.db, папка gotosocial (id 23), dashboard_provisioning содержит запись.
  • Openspec: change add-gotosocial-dashboard → spec gotosocial-monitoring (в /opt/monitoring), archive; коммит ee92496 (monitoring); STATUS.md gotosocial → 275385c.

Git (эта сессия)

  • /opt/gotosocial: 568335a (governance), 275385c (status) — запушены на gitverse.
  • /opt/monitoring: ee92496 — запушен на gitverse + mirror-sync на gitea (HTTP 200, POST /api/v1/repos/estorozhenko/monitoring/mirror-sync, токен из git-tokens.env).
  • mirror-sync gitea: http://gitea.nixg.ru → 308 на https:// — использовать https или python urllib с redirect.

Находка (не исправлена)

  • config.py:45 — дефект == вместо != (исходники GtS, /tmp/gts-src) — зафиксировать, не фикс.