Каждая кнопка в разделе «Сервис» просто запускает shell-скрипт из директории /tools внутри контейнера. Ничто не мешает запускать те же скрипты снаружи — командой docker exec с хоста. Это открывает несколько полезных сценариев: обновление библиотеки по расписанию без участия человека, восстановление после сбоев, когда веб-интерфейс недоступен, и доступ к базе через psql без установки клиента на хост.

Как правильно вызывать: docker exec -u www-data

docker exec -u www-data flibusta-fpm /tools/update_daily.sh

Ключевой момент — -u www-data. Внутри контейнера php-fpm работает от пользователя www-data (uid 82), и всё в /cache и /sql принадлежит ему. Если запустить скрипт от root (а docker exec по умолчанию делает именно так), созданные им файлы — скачанные дампы, обложки, файлы блокировок, лог — окажутся с владельцем root, и потом PHP не сможет их перезаписать. Симптомы такой ошибки разнообразны и неочевидны («Скачать базу» молча не обновляет файлы, обложки перестали кэшироваться), поэтому лучше сразу взять за правило: любой docker exec для библиотеки — с -u www-data.

Если это всё-таки случилось, вылечить просто: перезапуск контейнера (docker restart flibusta-fpm) — скрипт входа выполняет chown -R www-data /cache /sql при каждом старте.

Имя контейнера flibusta-fpm задано в container_name шаблона. В устаревшей конфигурации all-in-one контейнер называется <проект>-php-fpm-1; уточнить можно через docker ps.

Переменные окружения (FLIBUSTA_URL, параметры БД, пути к секретам) docker exec наследует от контейнера, поэтому скрипты работают ровно так же, как из веб-интерфейса.

Какие скрипты есть

Скрипт Кнопка в «Сервисе» Блокировки Примечания
/tools/getsql.sh Скачать базу данных admin пропускает файлы с неизменившимся ETag
/tools/app_import_sql.sh Обновить базу данных admin + db библиотека в режиме техобслуживания на время выполнения
/tools/getcovers.sh Скачать обложки admin проверяет скачанные архивы через unzip -t
/tools/update_daily.sh Скачать последние обновления admin кладёт архивы в /cache/local; чистит ETag-записи старше 90 дней
/tools/app_reindex.sh Сканирование ZIP admin + db быстрый: читает только имена файлов
/tools/add_torrent_books.sh <tmpdir> <magnet или .torrent> Добавить книги из торрента admin tmpdir нужно создать самому в /cache/tmp
php /tools/merge_local_books.php (часть импорта) — переносит добавленные вручную книги обратно после импорта
php /tools/update_zip_list.php (часть сканирования) — сам индексатор: заполняет таблицу book_zip и файл /cache/zip_index.php, без блокировок
php /tools/build_zip_index.php — — собирает /cache/zip_index.php из таблицы book_zip, если файла нет; запускается при старте контейнера. С ключом --force перестроит существующий
php /tools/cache_bump.php (часть импорта и сканирования) — сбрасывает кэш описаний книг в Redis. Без Redis — ничего не делает и завершается успешно

«admin» — общая блокировка операций (/cache/locks/adminop.lock): второй скрипт одновременно не запустится и завершится с сообщением failed to obtain admin op lock. «db» — блокировка БД (/cache/locks/dbupdate.lock): пока она удерживается, веб-интерфейс показывает страницу техобслуживания. Обе блокировки — flock, снимаются автоматически при завершении процесса, в том числе аварийном.

Скрипты пишут ход выполнения в stdout (по-русски, это то, что видно в веб-интерфейсе) и служебные отметки в stderr.

Показывать ход выполнения в веб-интерфейсе

Веб-интерфейс определяет «идёт операция» по блокировке, а текст берёт из файла /cache/status. Если скрипт запущен через docker exec, страница «Сервис» покажет спиннер, но с текстом предыдущей операции. Чтобы администратор в браузере видел актуальный вывод, перенаправьте stdout в тот же файл:

docker exec -u www-data flibusta-fpm sh -c '/tools/update_daily.sh > /cache/status 2>&1'

Обёртка sh -c нужна, чтобы перенаправление выполнилось внутри контейнера, а не на хосте. stdbuf -o0 в веб-интерфейсе добавлен ради построчного вывода без буферизации; для cron это не принципиально.

Пример: обновление библиотеки по cron

Самый востребованный сценарий. Флибуста выкладывает ежедневные добавления в /daily/, а полный дамп базы обновляется раз в несколько дней. Разумный график: каждую ночь — обновления и пересканирование, раз в неделю — свежий дамп и импорт.

Откройте crontab пользователя, у которого есть право на docker (root или член группы docker):

sudo crontab -e
# Flibusta-at-home: ежедневные обновления и пересканирование архивов, 04:10
10 4 * * * docker exec -u www-data flibusta-fpm sh -c '/tools/update_daily.sh > /cache/status 2>&1 && /tools/app_reindex.sh >> /cache/status 2>&1'

# Flibusta-at-home: свежий дамп БД и полный импорт, понедельник 03:00
0 3 * * 1 docker exec -u www-data flibusta-fpm sh -c '/tools/getsql.sh > /cache/status 2>&1 && /tools/app_import_sql.sh >> /cache/status 2>&1'

# Flibusta-at-home: обложки, первое число месяца
30 3 1 * * docker exec -u www-data flibusta-fpm sh -c '/tools/getcovers.sh > /cache/status 2>&1'

Несколько замечаний:

  • && между скриптами гарантирует, что импорт не начнётся, если скачивание завершилось с ошибкой. Скрипты завершаются ненулевым кодом при невозможности взять блокировку, так что случайное наложение на операцию, запущенную из браузера, просто отменит cron-задание, а не сломает что-то.
  • Импорт переводит библиотеку в режим техобслуживания на минуты или десятки минут (зависит от диска и процессора). Ставьте его на время, когда никто не читает.
  • Время в cron — часовой пояс хоста, а не контейнера.
  • Вывод cron-задания уходит в /cache/status и виден в «Сервисе» как «лог последней операции». Если хочется получать письма об ошибках, уберите перенаправление 2>&1 — stderr тогда пойдёт в почту cron.

Если на хосте systemd и хочется видеть историю запусков в journalctl, тот же вызов оформляется как .service + .timer; содержательно ничего не меняется.

Пример: восстановление, когда веб-интерфейс недоступен

Реальный случай: импорт прерван перезапуском хоста посреди операции. Таблицы могут оказаться частично заполненными, библиотека — в странном состоянии. Лечится повторным полным импортом с консоли:

docker exec -u www-data flibusta-fpm sh -c '/tools/app_import_sql.sh > /cache/status 2>&1'
docker exec -u www-data flibusta-fpm tail -f /cache/log/dbupdate.log

Дампы уже лежат в /sql, скачивать заново не нужно (если .gz уже распакованы, gzip пожалуется, но импорт продолжится — это не ошибка).

Пример: psql к базе библиотеки

В образе есть клиент Postgres, а скрипт dbinit.sh умеет собрать строку подключения из переменных окружения и секрета с паролем:

docker exec -it -u www-data flibusta-fpm sh -c '. /tools/dbinit.sh; $SQL_CMD'

Дальше — обычный psql. Пара запросов, которые бывают полезны:

-- кто есть в библиотеке
SELECT id, username, is_admin, created_at FROM users ORDER BY id;

-- неудачные попытки входа за сутки
SELECT attempt_time, ip_address, username, outcome
  FROM login_attempts WHERE outcome > 0 AND attempt_time > now() - interval '1 day'
  ORDER BY attempt_time DESC;

-- какие архивы и диапазоны id знает библиотека
SELECT filename, start_id, end_id, usr FROM book_zip ORDER BY usr, start_id;

Сменить пароль пользователя из psql нельзя без вычисления bcrypt-хэша, но можно сделать это в одну строку через PHP из того же контейнера:

docker exec -u www-data flibusta-fpm sh -c \
  '. /tools/dbinit.sh; H=$(php -r "echo password_hash(\"НовыйПароль\", PASSWORD_DEFAULT);"); \
   $SQL_CMD -c "UPDATE users SET password_hash='"'"'$H'"'"' WHERE username='"'"'reader'"'"'"'

(Вложенные кавычки выглядят устрашающе, но проще, чем ставить PHP на хост. Для администратора есть более простой путь — через FLIBUSTA_APP_ADMIN, см. переменные окружения.)

Где смотреть логи

Что Где
лог контейнера (старт, инициализация БД, ошибки PHP через error_log) docker logs flibusta-fpm
импорт дампа /cache/log/dbupdate.log
индексация архивов /cache/log/update_zip_list.log
миграции схемы при старте /cache/log/postgres_migration.log
последняя операция из «Сервиса» или cron /cache/status
неудачные попытки входа /cache/login_attempts/flibusta_login_attempts.log
доступ и ошибки nginx у reverse proxy; в шаблонах — flibusta.access.log и flibusta.error.log

Всё, что в /cache, доступно и с хоста по пути смонтированной директории — docker exec для чтения логов не обязателен.

Диагностика: сколько запросов к базе делает страница

Переменная окружения FLIBUSTA_DEBUG_DB=true добавляет в лог контейнера по строке на каждый запрос:

docker logs -f flibusta-fpm | grep dbstats
dbstats /fb2.php?id=123 connected=0 statements=0
dbstats /book/view/123 connected=1 statements=4

connected показывает, открывалось ли вообще соединение с Postgres, statements — сколько запросов выполнено. Полезно, чтобы убедиться, что кэш работает, или найти страницу, которая внезапно стала делать слишком много запросов. Подробности — в статье о кэше и производительности.

В обычной работе переменную держите выключенной: она пишет строку на каждый запрос, включая каждую картинку.