diff --git a/STATUS.md b/STATUS.md index 9756f73..5f46f2a 100644 --- a/STATUS.md +++ b/STATUS.md @@ -1,34 +1,54 @@ # GoToSocial — Статус -Обновлено: 2026-09-06 (сессия 2026-09-06_19xx) +Обновлено: 2026-09-06 (поздний вечер, деплой завершён) ## Текущее состояние -Проект развёртывания GoToSocial-ноды на social.dedinit.ru оформлен: создан каталог /opt/gotosocial, OpenSpec change deploy-gotosocial (валиден), все рабочие файлы (compose, config, .env, backup.sh, README) готовы и запушены в git. **Сервис ещё НЕ запущен** — это следующий шаг. DNS social.dedinit.ru → 87.242.100.206 (vps02) создан пользователем. +GoToSocial **запущен и работает** на social.dedinit.ru: контейнер Up, HTTPS 200, админ создан. +Split-domain работает: аккаунты `@user@dedinit.ru`, хост social.dedinit.ru, apex-webfinger отдаёт JSON. +Ежедневный cron-бэкап (02:00) активен и проверен. ## Сделано -- 2026-09-06: исследование развёртывания GoToSocial (доки v0.22.1, split-domain, Docker) -- 2026-09-06: каталог /opt/gotosocial, OpenSpec init + change `deploy-gotosocial` (proposal/spec×2/design/tasks), `openspec validate` ✅ -- 2026-09-06: docker-compose.yml (v0.22.1, SQLite, порт 8080, volume ./data, net 172.29.0.0/16) -- 2026-09-06: config.yaml (host=social.dedinit.ru, account-domain=dedinit.ru, SMTP Jino, metrics, log json) -- 2026-09-06: .env (SMTP-пароль; в git исключён), backup.sh (SQLite VACUUM INTO + медиа, ротация 7д/30д, ЯД), README.md, .gitignore -- 2026-09-06: git init + commit d385d8b -- 2026-09-06: gitverse репо `kpa39l/gotosocial` создан (API, Bearer+Accept object+json), main запушен -- 2026-09-06: gitea.nixg.ru pull-mirror `estorozhenko/gotosocial` (интервал 8ч), первая синхронизация ✅ (коммит d385d8b) +### Запуск на bigbox (шаг 1) +- 2026-09-06: тег образа `0.22.1` (не `v0.22.1` — оригинала не существует), порт `8082:8080` + (8080 на bigbox занят NetBox!), права `data/` → 1000:1000 +- 2026-09-06: конфиг через `GTS_*` env — docker-образ НЕ читает смонтированный config.yaml + (падал «host must be set»), .cache для Wazero +- 2026-09-06: админ `estorozhenko` создан/confirmed/promoted; HTTPS LE на social.dedinit.ru ✅ + +### Caddy vps02 (шаг 2) +- 2026-09-06: Caddyfile: `social.dedinit.ru { reverse_proxy 10.8.0.2:8082 }` + reload + (бэкап Caddyfile.bak-1788723018), сертификат LE выпущен сразу, сайт 200 + +### Split-domain apex Jino (шаг 3) +- 2026-09-06: .htaccess/mod_rewrite на Jino НЕ работают (проверено) → статический ответ: + - `/.well-known/webfinger?resource=...` → Apache 301 → `/webfinger/` → 200 JSON (index.html) + - `/.well-known/nodeinfo` → 301 → `/nodeinfo/` → 200 JSON + - `/.well-known/host-meta` → 200 XRD (text/xml) + - Файлы в `/dedinit.ru/.well-known/` (Jino) + `/opt/dedinit.ru/static/.well-known/` (в git, Hugo копирует) + +### Крон бэкапа (шаг 4) +- 2026-09-06: backup.sh переписан на SQLite Backup API через python3 (sqlite3 CLI нет ни на хосте, + ни в контейнере); медиа из data/ (это и есть /gotosocial/storage), SQLite отдельно +- 2026-09-06: cron `gotosocial-backup-daily` (id 67308da56b6d), daily 02:00, no_agent, deliver local, + тихий (пустой stdout при успехе), проверен немедленным запуском (3 бэкапа 19:41-19:42) +- Локально 7 дней, ЯД 30 дней + +### Git +- 2026-09-06: gotosocial commit d9951b6 запушен на gitverse (56f228a..d9951b6) +- 2026-09-06: dedinit.ru commit b049cb2 запушен на gitverse (3d2f07b..b049cb2) ## В работе / Следующие шаги -- [ ] **Развернуть сервис на bigbox**: `cd /opt/gotosocial && docker compose up -d` + создание админа estorozhenko (нужен пароль от пользователя) -- [ ] **Caddy на vps02**: блок `social.dedinit.ru { reverse_proxy 10.8.0.2:8080 }` + reload (нужен доступ vps02) -- [ ] **Split-domain apex**: .well-known редиректы (webfinger/nodeinfo/host-meta) на dedinit.ru (Jino) — подготовить точные правила -- [ ] Проверить HTTPS (сертификат LE), webfinger, SMTP-письмо, /metrics -- [ ] Настроить cron бэкапа (backup.sh готов; расписание ещё нет) +- [ ] Проверить SMTP-письмо (регистрация/восстановление пароля) — через админку +- [ ] Мониторинг: пробросить :9464 (метрики уже слушают), job в prometheus.yml, дашборд Grafana + (инструкция по метрикам GtS получена от пользователя 2026-09-06) +- [ ] Логи в json-формате при желании (log-format: json) — по умолчанию logfmt ## Отложено (post-MVP, по решению пользователя) - Мониторинг бэкапов (метрики в Prometheus + дашборд Grafana) -- Дашборд Grafana для GtS - Импорт из Telegram ## Как запустить / проверить @@ -36,20 +56,20 @@ ```bash cd /opt/gotosocial docker compose up -d -curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8080/ # 200 -curl -s http://127.0.0.1:8080/metrics | grep -E 'go_goroutines|gin_|bun_' +curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8082/ # 200 +curl -s http://127.0.0.1:9464/metrics | head # метрики (в контейнере) curl -s 'https://social.dedinit.ru/.well-known/webfinger?resource=acct:estorozhenko@dedinit.ru' +curl -s 'https://dedinit.ru/.well-known/webfinger?resource=acct:estorozhenko@dedinit.ru' # apex JSON bash backup.sh && ls -lh backups/ ``` ## Ключевые артефакты -- /opt/gotosocial/docker-compose.yml, config.yaml, .env, backup.sh, README.md -- /opt/gotosocial/openspec/changes/deploy-gotosocial/ (change) +- /opt/gotosocial/docker-compose.yml, .env, backup.sh, README.md (config.yaml — reference, НЕ читается образом) - gitverse.ru/kpa39l/gotosocial (истина), gitea.nixg.ru/estorozhenko/gotosocial (зеркало) +- /opt/dedinit.ru/static/.well-known/ (apex, в git b049cb2) ## Открытые вопросы -- Пароль админа estorozhenko для первого запуска -- Готовность vps02 к правке Caddyfile (нужен SSH) -- Точные .well-known редиректы на apex (Jino) — подготовить и применить \ No newline at end of file +- Пароль админа: создан с паролем из сессии (если менялся — обновить в заметках) +- ZFS-бэкапы/другие ротации не требуются (хватает local 7д + ЯД 30д) \ No newline at end of file diff --git a/backup.sh b/backup.sh index 999853b..cc1c54d 100755 --- a/backup.sh +++ b/backup.sh @@ -2,35 +2,52 @@ # ============================================================= # GoToSocial backup: SQLite consistent + медиа → backups/ # + копия на Яндекс.Диск (ротация 7 дней локально / 30 на ЯД) +# +# Топология: /opt/gotosocial/data → /gotosocial/storage (контейнер) +# data/sqlite.db + media лежат прямо в data/ (storage-маунт) +# SQLite: Backup API через python3 (sqlite3 CLI не установлен) +# Тихий: stdout пуст при успехе (для no_agent cron), не-ноль при ошибке # ============================================================= set -euo pipefail BASE_DIR="/opt/gotosocial" DATA_DIR="${BASE_DIR}/data" BACKUP_DIR="${BASE_DIR}/backups" -YANDEX_DIR="/mnt/yandex-disk/backup/gotosocial-backups" +YANDEX_MOUNT="/mnt/yandex-disk" +YANDEX_DIR="${YANDEX_MOUNT}/backup/gotosocial-backups" +STAGE="${BACKUP_DIR}/stage" TS="$(date +%Y%m%d_%H%M%S)" -# --- SQLite consistent: VACUUM INTO (не горячая копия файла) --- -SQLITE_TMP="${BACKUP_DIR}/sqlite-consistent-${TS}.db" mkdir -p "${BACKUP_DIR}" -sqlite3 "${DATA_DIR}/sqlite.db" "VACUUM INTO '${SQLITE_TMP}';" +rm -rf "${STAGE}" && mkdir -p "${STAGE}" -# --- Сбор архива: consistent db + медиа --- +# --- Компактный снапшот БД через SQLite Backup API (online, без конфликтов) --- +python3 - "${DATA_DIR}/sqlite.db" "${STAGE}/sqlite.db" <<'PYEOF' +import sqlite3, sys +src, dst = sys.argv[1], sys.argv[2] +s = sqlite3.connect(src) +d = sqlite3.connect(dst) +with d: + s.backup(d) +d.close() +s.close() +PYEOF + +# --- Медиа копируем в stage (без WAL/SHM, с сохранением структуры) --- +# Исключаем служебные sqlite-файлы из data/, чтобы не дублировать БД +(cd "${DATA_DIR}" && tar -cf - --exclude='sqlite.db*' .) | tar -xf - -C "${STAGE}" + +# --- Итоговый архив: consistent db + медиа --- ARCHIVE="${BACKUP_DIR}/gotosocial_${TS}.tar.gz" -tar -C "${DATA_DIR}" -czf "${ARCHIVE}" \ - --transform="s|sqlite-consistent-${TS}.db|sqlite.db|" \ - "${SQLITE_TMP#${DATA_DIR}/}" storage 2>/dev/null \ - || tar -C "${BACKUP_DIR}" -czf "${ARCHIVE}" "sqlite-consistent-${TS}.db" -C "${DATA_DIR}" storage -rm -f "${SQLITE_TMP}" +tar -C "${STAGE}" -czf "${ARCHIVE}" . # --- Архив секретов (.env) отдельно --- ENV_ARCHIVE="${BACKUP_DIR}/gotosocial_env_${TS}.tar.gz" tar -C "${BASE_DIR}" -czf "${ENV_ARCHIVE}" .env # --- Копия на Яндекс.Диск --- -if ! mountpoint -q "${YANDEX_DIR%/backup/*}"; then - echo "ERROR: Яндекс.Диск не примонтирован (${YANDEX_DIR%/backup/*})" >&2 +if ! mountpoint -q "${YANDEX_MOUNT}"; then + echo "ERROR: Яндекс.Диск не примонтирован (${YANDEX_MOUNT})" >&2 exit 1 fi mkdir -p "${YANDEX_DIR}" @@ -40,6 +57,7 @@ cp -p "${ARCHIVE}" "${ENV_ARCHIVE}" "${YANDEX_DIR}/" find "${BACKUP_DIR}" -maxdepth 1 -type f -name 'gotosocial_*' -mtime +7 -delete find "${YANDEX_DIR}" -maxdepth 1 -type f -name 'gotosocial_*' -mtime +30 -delete -echo "OK: ${ARCHIVE}" -echo "OK: ${ENV_ARCHIVE}" -ls -lh "${ARCHIVE}" "${ENV_ARCHIVE}" \ No newline at end of file +rm -rf "${STAGE}" + +# Успех — тихо (для no_agent cron) +exit 0 \ No newline at end of file