Skip to main content
  1. Posts/
  2. Self-Hosting/

Grimmory - a self-hosted library and reader for your book collection

··1309 words·7 mins· loading · loading · ·
Stilicho2011
Author
Stilicho2011
Writing about homelab, self-hosting, automation and open-source solutions
Table of Contents
Self-Hosting - This article is part of a series.
Part : This Article

If you enjoyed this article, you can support the author by becoming a sponsor on Boosty.

In one of my recent articles I talked about Booklore - a platform for managing your own web library.

In another article, dedicated to the best open-source apps of 2025, I named this app one of the discoveries of the year.

By a strange coincidence, just a couple of days before publishing the video review of this app, the author deleted the project.


What happened to Booklore: breaking down the situation
#

The removal of the Booklore project came as a surprise to users, but if you look through the developer’s statements and the discussions on Reddit/GitHub, the real picture becomes clear.


The developer’s position
#

The project’s author published a thread on Reddit titled:

“My side of the story, from the developer of BookLore”

It was an attempt to explain what was going on, but the key factor was not just his stance, but rather the users’ reaction.

One telling comment:

“you removed the API docs without notice”

What this actually meant:
#

  • changes were made without warning;
  • backward compatibility was broken.

As a result, both users and integration developers suffered.


Conflict with the community
#

Over time, systemic problems in the developer’s interaction with users accumulated.

The main grievances included:
#

  • significant changes, up to and including breaking changes, made without notice;
  • functionality being removed or broken;
  • feedback that was weak to the point of nonexistent;

The result was a classic open-source conflict:
developer vs. community


The abrupt disappearance of the project
#

At the moment of removal, users noted:

  • the GitHub repository became inaccessible (404)
  • the Discord server disappeared
  • there was no official announcement

This looked like a purely emotional decision - a kind of reaction to criticism that was at times more than fair - and it was ugly toward ordinary users who had no idea what was going on.


Fork and licensing issues
#

An additional factor was the disputes around the license (AGPL-3.0).

What happened:
#

  • forks of the project appeared (for example, Grimmory, the hero of today’s article)
  • possible license violations were discussed
  • conflicts arose around the use of the code

The latter is actually far from rare - just look at the situation around OnlyOffice and Nextcloud.


Growing negativity around the project
#

Even before the removal, there were warning signs:

  • bugs
  • discussions of “is it still worth using Booklore”
  • criticism of architectural decisions
  • questions about telemetry. Yes, there were questions about that too.

In other words, the project was already under pressure from its users.


Bottom line: the project was removed
#

In fact, Booklore’s removal wasn’t caused by any single reason, but by a whole chain of events.


The main takeaway
#

This isn’t the usual “the developer got burned out” story, like what recently happened with the very good project Palmr.

It’s more a case of poor communication → conflict → toxic environment → abrupt project removal.


Your humble narrator knew nothing about any of this and calmly published a video about this project on various video platforms. Naturally, people wrote in the comments telling me I was wrong, that the project was already dead, and that the video was outdated. Fine - I have no conflict with the community, so here’s a replacement for you. As I mentioned above, the original Booklore project was quickly forked by the community. Since the original Booklore was published under the AGPL license, the Grimmory project is essentially a one-to-one relicensed Booklore, just with a new name. If you look at the config files, the original docker-compose file still uses the variable name “booklore.” In any case, since I ended up in a situation where I published an article that was already outdated by the publication date, I’m fixing that now.

Below is a working version of the docker-compose file and the environment file.

services:                               # Секция описания сервисов (контейнеров)

  booklore:                             # Имя сервиса BookLore
    image: grimmory/grimmory:latest     # Docker-образ BookLore из Docker Hub (тег latest)
    # image: ghcr.io/booklore-app/booklore:latest
    # Альтернативный образ из GitHub Container Registry (закомментирован)
    container_name: grimmory            # Явное имя контейнера в Docker
    environment:                        # Переменные окружения контейнера
      - USER_ID=${APP_USER_ID}          # UID пользователя для работы контейнера (права на файлы)
      - GROUP_ID=${APP_GROUP_ID}        # GID группы для файлов и каталогов
      - TZ=${TZ}                        # Часовой пояс контейнера
      - DATABASE_URL=${DATABASE_URL}    # URL подключения к базе данных MariaDB
      - DATABASE_USERNAME=${DB_USER}    # Имя пользователя базы данных
      - DATABASE_PASSWORD=${DB_PASSWORD} # Пароль пользователя базы данных
      - BOOKLORE_PORT=${BOOKLORE_PORT}  # Внутренний порт BookLore
    depends_on:                         # Зависимости сервиса
      mariadb:                          # Зависимость от сервиса mariadb
        condition: service_healthy      # Запуск только после успешного healthcheck БД
    ports:
      - "${BOOKLORE_PORT}:${BOOKLORE_PORT}"   # Проброс порта: host → container (обычно не нужен при использовании Traefik)
    volumes:
      - ./data:/app/data                # Данные приложения BookLore
      - ./books:/books                  # Каталог с библиотекой книг
      - ./bookdrop:/bookdrop            # Папка для автоматического импорта книг
    healthcheck:                        # Проверка работоспособности контейнера
      test: wget -q -O - http://localhost:${BOOKLORE_PORT}/api/v1/healthcheck
      # HTTP-запрос к встроенному healthcheck API BookLore
      interval: 60s                     # Интервал между проверками
      retries: 5                        # Количество попыток до признания контейнера unhealthy
      start_period: 60s                 # Время ожидания перед началом проверок
      timeout: 10s                      # Таймаут одной проверки
    restart: unless-stopped             # Автоперезапуск контейнера (кроме ручной остановки)
    networks:
      proxy:                            # Подключение к внешней сети proxy (Traefik)
    labels:                             # Метки Docker для интеграции с Traefik
      - "traefik.enable=true"           # Включаем обработку контейнера Traefik
      - "traefik.http.routers.grimmory.entrypoints=web" # HTTP-вход (порт 80)
      - "traefik.http.routers.grimmory.rule=Host(`grimmory.stilicho.ru`)" # Направляем трафик с домена grimmory.stilicho.ru в этот контейнер
      - "traefik.http.middlewares.grimmory-https-redirect.redirectscheme.scheme=https" # Middleware для редиректа HTTP → HTTPS
      - "traefik.http.routers.grimmory.middlewares=grimmory-https-redirect" # Применяем middleware редиректа к HTTP-маршруту
      - "traefik.http.routers.grimmory-secure.entrypoints=websecure" # HTTPS-вход (порт 443)
      - "traefik.http.routers.grimmory-secure.rule=Host(`grimmory.stilicho.ru`)" # HTTPS-маршрут для того же домена
      - "traefik.http.routers.grimmory-secure.tls=true" # Включаем TLS (HTTPS)
      - "traefik.http.routers.grimmory-secure.service=grimmory"  # Привязываем HTTPS-роутер к сервису booklore
      - "traefik.http.services.grimmory.loadbalancer.server.port=6060" # Внутренний порт BookLore внутри контейнера
      - "traefik.docker.network=proxy" # Указываем Traefik, в какой Docker-сети искать контейнер
#
  mariadb:                              # Сервис базы данных MariaDB
    image: lscr.io/linuxserver/mariadb:11.4.5
    # Образ MariaDB от LinuxServer.io (стабильный и удобный)
    container_name: mariadb             # Явное имя контейнера
    environment:                        # Переменные окружения MariaDB
      - PUID=${DB_USER_ID}              # UID владельца файлов БД
      - PGID=${DB_GROUP_ID}             # GID владельца файлов БД
      - TZ=${TZ}                        # Часовой пояс
      - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}       # Пароль root-пользователя БД
      - MYSQL_DATABASE=${MYSQL_DATABASE}       # Имя базы данных, создаваемой при первом запуске
      - MYSQL_USER=${DB_USER}       # Пользователь БД
      - MYSQL_PASSWORD=${DB_PASSWORD}    # Пароль пользователя БД
    volumes:
      - ./mariadb/config:/config        # Каталог с данными и конфигурацией MariaDB
    restart: unless-stopped             # Автоперезапуск контейнера
    healthcheck:                        # Проверка доступности БД
      test: [ "CMD", "mariadb-admin", "ping", "-h", "localhost" ]
      interval: 5s                      # Интервал проверки
      timeout: 5s                       # Таймаут проверки
      retries: 10                       # Количество попыток
    networks:
      proxy:                            # Подключение к сети proxy (Traefik)

networks:
  proxy:                                # Определение сети proxy
    external: true                      # Сеть уже существует и не создаётся Docker самостоятельно

Environment file

# =========================================================
# 🎯 BookLore - основные настройки приложения
# =========================================================

APP_USER_ID=1000
# UID пользователя на хосте, от имени которого
# BookLore будет работать внутри контейнера.
# Нужен для корректных прав доступа к volume.
APP_GROUP_ID=1000
# GID группы на хосте.
# Должен совпадать с владельцем каталогов data / books / bookdrop.
TZ=Europe/Moscow
# Часовой пояс контейнеров.
# Используется для логов, планировщиков и временных меток.
BOOKLORE_PORT=6060
# Порт, на котором BookLore слушает внутри контейнера.
# Также используется Traefik как внутренний порт сервиса.
# =========================================================
# 🗄️ Подключение BookLore к базе данных MariaDB
# =========================================================
DATABASE_URL=jdbc:mariadb://mariadb:3306/grimmory
# JDBC-строка подключения к MariaDB:
# - mariadb        → имя сервиса в docker-compose
# - 3306           → стандартный порт MariaDB
# - grimmory       → имя базы данных
DB_USER=grimmory
# Пользователь базы данных,
# под которым BookLore подключается к MariaDB.
DB_PASSWORD=ChangeMe_BookLoreApp_2025!
# Пароль пользователя базы данных.
# ⚠️ ОБЯЗАТЕЛЬНО сменить в продакшене.
# =========================================================
# 🔧 Настройки контейнера MariaDB (инициализация)
# =========================================================
DB_USER_ID=1000
# UID пользователя, от имени которого
# MariaDB пишет данные в volume.
DB_GROUP_ID=1000
# GID группы для файлов базы данных.
MYSQL_ROOT_PASSWORD=ChangeMe_MariaDBRoot_2025!
# Пароль root-пользователя MariaDB.
# Используется только для администрирования БД.
MYSQL_DATABASE=grimmory
# Имя базы данных, которая будет автоматически
# создана при первом запуске контейнера MariaDB.
Self-Hosting - This article is part of a series.
Part : This Article

Related