Любой человек, всерьёз увлекающийся чтением, рано или поздно сталкивается с одной и той же проблемой. Книг становится много, форматы у них разные, на одном устройстве лежит epub, на другом mobi, на третьем pdf, и каждый раз приходится мучительно вспоминать, где именно осталась недочитанная глава. Облачные читалки решают вопрос лишь отчасти - они закрытые, привязывают к одному магазину, имеют свои ограничения по форматам и не дают полного контроля над собственной коллекцией. Хочется чего-то простого и собственного, что работает по принципу "положил книгу - и она доступна везде". Calibre именно такое решение и предлагает.

Сам по себе Calibre широко известен как настольная программа для управления электронными книгами на Linux, Windows и macOS. Эта часть проекта позволяет хранить локальную библиотеку, конвертировать между форматами, редактировать метаданные, синхронизироваться с устройствами вроде Kindle. Но у Calibre есть и серверная сторона, о которой знают далеко не все. Серверный компонент превращает обычный Linux-узел в персональную книжную полку, доступную с любого устройства через браузер.

С таким сервером открываются интересные возможности. Можно читать книги из любой точки мира, не таская с собой устройство с локальной копией. Можно быстро передавать книги на смартфон или планшет без проводов и кабелей. Можно делиться чтением с друзьями и родственниками, выдавая им логины и пароли. Можно читать прямо в браузере без установки дополнительного софта. Ниже разобран полный путь развёртывания такого сервера на Ubuntu 22.04 - от подготовки брандмауэра до подключения TLS-сертификата от Let's Encrypt.

Подготовительные требования и базовое окружение для развёртывания личной книжной полки

Чтобы пройти этот путь без сюрпризов, понадобится сервер на Ubuntu 22.04 - желательно свежий, без хвостов от предыдущих экспериментов. Доступ должен быть из-под обычного пользователя с правами sudo. Постоянная работа из-под root считается дурным тоном с давних времён, и для сетевых сервисов это особенно критично.

В системе должен быть включён и работать брандмауэр UFW (Uncomplicated Firewall) - стандартное средство фильтрации сетевого трафика на Ubuntu. Также нужно полное доменное имя (FQDN), направленное A-записью на IP сервера. Без домена не получится выпустить TLS-сертификат, а без шифрования передача учётных данных будет небезопасна. В этом руководстве используется условный домен calibre.example.com - его нужно заменить на свой реальный.

Обновляем пакеты до последних версий перед началом:

$ sudo apt update && sudo apt upgrade

Эта команда сначала обновляет индекс репозиториев, а затем устанавливает все доступные обновления. Привычка делать update перед серьёзными работами экономит часы будущих разбирательств с устаревшими версиями.

Открытие портов HTTP и HTTPS в брандмауэре UFW для веб-доступа к серверу

Любая публикация веб-сервиса начинается с открытия нужных портов. Calibre будет крутиться внутри сервера на порту 8080, но снаружи трафик пойдёт через стандартные 80 и 443, которые проксирует Nginx. Эти два порта и нужно открыть.

Проверяем текущее состояние брандмауэра:

$ sudo ufw status

Ожидаемый вывод:

Status: active
To 
Action 
From
-- 
------ 
----
OpenSSH 
ALLOW 
Anywhere
OpenSSH (v6) 
ALLOW 
Anywhere (v6)

Видно, что разрешён только SSH - это базовая настройка любого правильно сконфигурированного сервера. Если вместо active в выводе inactive, нужно сначала включить UFW через sudo ufw enable, не забыв предварительно разрешить SSH, иначе можно потерять удалённый доступ.

Открываем порты для веб-трафика:

$ sudo ufw allow http
$ sudo ufw allow https

Использование имён http и https вместо номеров портов 80 и 443 - синтаксический сахар UFW. Брандмауэр сам подставит нужные номера из своей встроенной таблицы соответствий. Это удобнее и понятнее в логах.

Проверяем результат:

$ sudo ufw status

Ожидаемый вывод:

Status: active
To 
Action 
From
-- 
------ 
----
OpenSSH 
ALLOW 
Anywhere
80/tcp 
ALLOW 
Anywhere
443/tcp 
ALLOW 
Anywhere
OpenSSH (v6) 
ALLOW 
Anywhere (v6)
80/tcp (v6) 
ALLOW 
Anywhere (v6)
443/tcp (v6) 
ALLOW 
Anywhere (v6)

В списке появились новые правила для HTTP и HTTPS трафика, причём как для IPv4, так и для IPv6. Брандмауэр готов пропускать веб-запросы.

Установка Calibre через официальный скрипт инсталлятора с подтягиванием свежей версии

Calibre присутствует в стандартном репозитории Ubuntu 22.04, но обычно там лежит относительно старая версия. Проект развивается активно, и каждая новая редакция приносит исправления багов и поддержку свежих форматов. Поэтому правильнее ставить через официальный скрипт инсталлятора с сайта проекта - так гарантированно получаешь самую актуальную сборку.

Сначала ставим зависимости, которые нужны для работы графических компонентов Calibre:

$ sudo apt install libopengl0 libxkbcommon-x11-0 libegl1 libfontconfig libgl1-mesa-glx

Странное наблюдение - зачем серверной версии графические библиотеки? Дело в том, что Calibre изначально создавался как настольное приложение, и его инсталлятор тянет за собой полный набор зависимостей вне зависимости от того, нужен GUI или нет. Без этих пакетов скрипт установки будет ругаться, хотя сам сервер потом работает в чисто консольном режиме. Это не самый изящный момент архитектуры, но мириться с ним приходится.

Скачиваем скрипт инсталлятора:

$ wget https://download.calibre-ebook.com/linux-installer.sh

Делаем его исполняемым:

$ chmod +x ./linux-installer.sh

Запускаем установку:

$ sudo ./linux-installer.sh

В процессе появятся предупреждения про отсутствие графического окружения - это нормально, инсталлятор всегда ругается на серверах. Сообщения можно спокойно игнорировать. Скрипт скачает последнюю версию Calibre, разместит файлы в /opt/calibre и создаст все нужные ссылки на бинарники.

Создание первой библиотеки и добавление пробной книги через утилиту calibredb

После установки нужно создать саму библиотеку - каталог, в котором будут жить книги вместе с метаданными и эскизами обложек. Для пробы возьмём книгу "Приключения Шерлока Холмса" Артура Конан Дойля из Project Gutenberg - бесплатной электронной библиотеки общественного достояния:

$ wget http://www.gutenberg.org/ebooks/1661.kindle.noimages -O adventuresofsherlockholmes.mobi

Файл сохраняется с понятным именем adventuresofsherlockholmes.mobi. На сайте проекта Гутенберг ссылки имеют технические имена вроде 1661.kindle.noimages, поэтому имеет смысл переименовывать при скачивании через флаг -O. Версия в формате Kindle (mobi) предпочтительнее по двум причинам - она нативно поддерживается читалками от Amazon и обычно имеет более качественную типографику, чем epub-варианты.

Создаём каталог для библиотеки:

$ mkdir calibre-library

Добавляем книгу в библиотеку через утилиту calibredb:

$ calibredb add adventuresofsherlockholmes.mobi --with-library calibre-library/

Параметр --with-library указывает путь к каталогу библиотеки. Без него calibredb попытается работать с библиотекой по умолчанию, которая ещё не существует. После выполнения команда выведет:

Added book ids: 1

Идентификатор 1 означает, что это первая книга в новой библиотеке. Дальше идентификаторы будут расти.

Если книг сразу несколько, можно добавлять их все одной командой через wildcard:

$ calibredb add *.mobi --with-library calibre-library/

Утилита переберёт все mobi-файлы в текущем каталоге и добавит их в библиотеку, проставив автоматически вытянутые из метаданных названия и авторов. Это удобнее, чем добавлять по одной, особенно если в коллекции десятки или сотни книг.

Запуск сервера Calibre и проверка веб-интерфейса в браузере

Книги готовы, пора запустить сервер:

$ calibre-server calibre-library

Команда calibre-server принимает путь к библиотеке как аргумент. После старта выводится подобное сообщение:

calibre server listening on 0.0.0.0:8080
OPDS feeds advertised via BonJour at: your_server_ip port: 8080

Адрес 0.0.0.0:8080 означает, что сервер слушает все сетевые интерфейсы на восьмом тысяче восьмидесятом порту. OPDS - это специальный протокол для каталогов электронных книг, который понимают многие читалки и приложения для управления библиотеками. BonJour - механизм автоматического обнаружения сервисов в локальной сети, удобно для быстрого подключения с домашних устройств.

Чтобы посмотреть на сервер из браузера, нужно временно открыть порт 8080:

$ sudo ufw allow 8080

Открываем браузер и переходим на http://<yourserverIP>:8080/. Появится приветственная страница Calibre с тёмной или светлой темой в зависимости от системных настроек. Кликаем на ссылку calibre-library и видим добавленную ранее книгу с обложкой и метаданными. Можно прямо в браузере перелистывать страницы, выбирать формат для скачивания, читать в браузере онлайн.

Останавливаем сервер через Ctrl + C в терминале.

Если стандартный порт 8080 чем-то не устраивает (занят другим сервисом, конфликтует с корпоративными политиками), можно запустить Calibre на любом другом:

$ calibre-server calibre-library --port 7654

Не забыть открыть выбранный порт в брандмауэре, иначе соединение не пройдёт.

Создание systemd юнита для автоматического запуска и устойчивой работы сервера

Запуск из терминала через calibre-server удобен для тестов, но в боевой эксплуатации не годится. Стоит закрыть SSH-сессию или перезагрузиться - и сервер пропадёт. Решение классическое - оформить запуск через systemd, чтобы служба поднималась автоматически при загрузке и перезапускалась при сбоях.

Создаём юнит-файл:

$ sudo nano /etc/systemd/system/calibre-server.service

Содержимое:

[Unit]
Description=Calibre Server
After=network.target

[Service]
Type=simple
User=<username>
Group=<username>
ExecStart=/opt/calibre/calibre-server /home/<username>/calibre-library --enable-local-write

[Install]
WantedBy=multi-user.target

Параметр --enable-local-write даёт серверу права на запись в библиотеку. Это важная тонкость - без этого флага нельзя добавлять новые книги через calibredb, пока сервер запущен. С флагом всё работает корректно одновременно.

Заменяем <username> на имя своего системного пользователя по всему файлу. Например, если пользователь зовётся reader, везде должно стоять reader. Сохраняем файл через Ctrl + W (или Ctrl + X в зависимости от версии nano) и подтверждаем Y.

Перечитываем конфигурацию systemd:

$ sudo systemctl daemon-reload

Эта команда обязательна после любых изменений в юнит-файлах. Без неё systemd работает по старому кешированному набору, и новые правки игнорируются.

Включаем автозапуск и стартуем службу:

$ sudo systemctl enable calibre-server
$ sudo systemctl start calibre-server

Первая команда прописывает запуск при загрузке системы, вторая поднимает сервис прямо сейчас.

Проверяем статус:

$ sudo systemctl status calibre-server

Ожидаемый вывод:

? calibre-server.service - Calibre Server
Loaded: loaded (/etc/systemd/system/calibre-server.service; enabled; vendor preset: enabled)
Active: active (running) since Mon 2022-07-25 07:23:42 UTC; 15s ago
Main PID: 1877 (BonJour)
Tasks: 13 (limit: 2241)
Memory: 53.3M
CPU: 762ms
CGroup: /system.slice/calibre-server.service
??1877 /opt/calibre/bin/calibre-server /home/<username>/calibre-library --enable-local-write

Jul 25 07:23:42 calibre systemd[1]: Started Calibre Server.
Jul 25 07:23:42 calibre calibre-server[1877]: QStandardPaths: XDG_RUNTIME_DIR not set, defaulting to '/tmp/runtime-<username>'
Jul 25 07:23:42 calibre calibre-server[1877]: calibre server listening on 0.0.0.0:8080
Jul 25 07:23:43 calibre calibre-server[1877]: OPDS feeds advertised via BonJour at: 69.28.84.201 port: 8080

Строка active (running) означает, что всё работает. Предупреждение про XDG_RUNTIME_DIR можно игнорировать - это последствие отсутствия графической сессии и на функциональность не влияет.

Защита библиотеки через включение базовой аутентификации с собственной учётной записью

По умолчанию доступ к Calibre открыт всем, кто знает адрес сервера. Для домашней сети это может быть приемлемо, но публиковать такую конфигурацию в интернет - всё равно что вешать ключи от квартиры на дверь. Надо включать защиту по логину и паролю.

Останавливаем сервер для внесения изменений:

$ sudo systemctl stop calibre-server

Calibre хранит учётные записи в SQLite-базе. Запускаем встроенный скрипт управления пользователями:

$ sudo calibre-server --manage-users

Появится меню с четырьмя опциями. Нажимаем 1 для добавления нового пользователя:

1) Add a new user
2) Edit an existing user
3) Remove a user
4) Cancel

What do you want to do? [1-4]: (Press 1)

Enter the username: howtoforge

Enter the new password for howtoforge:

Re-enter the new password for howtoforge, to verify:

User howtoforge added successfully!

Вводим имя пользователя (в примере оставлено howtoforge как условное имя) и пароль. Calibre проверит совпадение пароля при повторном вводе и сообщит об успешном добавлении.

Дальше нужно сказать сервису, что он должен требовать аутентификацию. Открываем юнит-файл:

$ sudo nano /etc/systemd/system/calibre-server.service

Добавляем флаг --enable-auth в конец строки ExecStart:

...
ExecStart=/opt/calibre/calibre-server "/home/<username>/calibre-library" --userdb "/home/<username>/.config/calibre/server-users.sqlite" --enable-local-write --enable-auth
...

В этой строке появилось два новых параметра. Первый - --userdb с путём к базе пользователей, которую Calibre создал на предыдущем шаге. Второй - сам --enable-auth, включающий проверку учётных данных. Без обоих параметров аутентификация работать не будет - один указывает где хранятся пароли, другой включает их использование.

Сохраняем файл, перечитываем systemd и запускаем сервис:

$ sudo systemctl daemon-reload
$ sudo systemctl start calibre-server

Открываем библиотеку в браузере - теперь вместо немедленного отображения каталога появится диалог авторизации. Вводим логин и пароль, попадаем внутрь. Всё, защита установлена.

Автоматическое добавление новых книг через cron-задачу с отслеживанием отдельной директории

Ручное добавление книг через calibredb работает, но при больших объёмах и регулярных пополнениях коллекции становится утомительным. Удобнее настроить автоматизацию - создать отдельный каталог-приёмник, куда просто кидаются новые книги, а скрипт по расписанию забирает их в библиотеку. Это самый быстрый способ держать коллекцию свежей: загрузил файл - и через несколько минут он уже в библиотеке.

Создаём каталог отслеживания:

$ mkdir ~/calibre-watch
$ cd ~/calibre-watch

Скачаем туда для примера "Войну и мир" Льва Толстого с того же Project Gutenberg:

$ wget https://www.gutenberg.org/ebooks/2600.kindle.images -O warandpeace.mobi

На этот раз берётся версия с картинками - на Project Gutenberg для разных книг доступны разные варианты. Calibre корректно обрабатывает обе вариации, так что выбор зависит от личных предпочтений.

Открываем редактор cron:

$ crontab -e

При первом запуске crontab спросит, какой редактор использовать:

no crontab for <username> - using an empty one

Select an editor. 
To change later, run 'select-editor'.

1. /bin/nano 
<---- easiest

2. /usr/bin/vim.basic

3. /usr/bin/vim.tiny

4. /bin/ed

Choose 1-4 [1]:

Нажимаем 1 для выбора nano - он самый простой и понятный. Открывается редактор с пустым crontab. Добавляем строку в конец файла:

*/5 * * * * calibredb add /home/<username>/calibre-watch/ -r --with-library http://localhost:8080#calibre-library --username mycalibreuser --password StrongPassword! && rm -r /home/<username>/calibre-watch/*

Эта длинная строка делает следующее. Конструкция */5 * * * * означает запуск каждые 5 минут (можно поменять на любой удобный интервал, например 0 * * * * для часового запуска). Команда calibredb add с параметром -r рекурсивно добавляет все файлы из указанного каталога. Параметр --with-library с URL означает работу через сетевой интерфейс сервера, а не напрямую с файлами библиотеки - это важно, поскольку сервер уже запущен и держит блокировки. Параметры --username и --password передают учётные данные для аутентификации. Конструкция через && после успешного добавления удаляет исходные файлы из watch-каталога, чтобы они не добавлялись повторно при следующем запуске.

Заменяем <username> на своё имя пользователя, mycalibreuser и StrongPassword! на свои реальные учётные данные Calibre. Сохраняем файл.

Через пять минут любой загруженный в /home/<username>/calibre-watch файл автоматически появится в библиотеке. Это удобно для интеграций - можно настроить downloader из RSS-ленты, поставить ScP-скрипт на смартфоне, прикрутить веб-форму загрузки.

Установка свежей версии Nginx через официальный репозиторий разработчиков

В стандартном репозитории Ubuntu 22.04 живёт относительно старая версия Nginx. Для современной конфигурации с TLS 1.3 и HTTP/2 хочется иметь свежую сборку. Подключаем официальный репозиторий nginx.org.

Импортируем подписной ключ Nginx:

$ curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor \
| sudo tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null

Команда выглядит замысловато, но логика прозрачная. Сначала curl скачивает ключ, потом gpg --dearmor преобразует его в бинарный формат, потом sudo tee сохраняет в стандартное место для ключей репозиториев. Перенаправление в /dev/null нужно, чтобы tee не дублировала вывод на экран.

Добавляем репозиторий стабильной ветки:

$ echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg arch=amd64] \
http://nginx.org/packages/ubuntu `lsb_release -cs` nginx" \
| sudo tee /etc/apt/sources.list.d/nginx.list

Параметр signed-by привязывает репозиторий к ранее установленному ключу - это часть современной модели безопасности apt. Конструкция lsb_release -cs подставляет кодовое имя текущего релиза Ubuntu (jammy для 22.04), что позволяет одной и той же команде работать на разных версиях системы.

Обновляем индекс и ставим Nginx:

$ sudo apt update
$ sudo apt install nginx

Проверяем результат:

$ nginx -v
nginx version: nginx/1.22.0

Версия 1.22 - последний стабильный релиз на момент написания оригинала. Все современные возможности TLS и HTTP/2 поддерживаются.

Получение TLS-сертификата от Let's Encrypt и настройка автоматического продления

Без шифрования передавать пароли по сети - значит делать подарок любому, кто способен прослушать трафик. Решение - сертификат от Let's Encrypt, бесплатной службы сертификации. Ставим Certbot через snap, поскольку snap-версия обновляется чаще и стабильнее.

Ubuntu 22.04 поставляется со Snapd по умолчанию. Обновляем основные компоненты:

$ sudo snap install core

Ставим сам Certbot:

$ sudo snap install --classic certbot

Параметр --classic разрешает snap-пакету выходить за пределы своего изолированного окружения. Для Certbot это нужно, поскольку он работает с системными файлами в /etc/letsencrypt и веб-сервером.

Создаём симлинк, чтобы команда certbot была доступна из обычного PATH:

$ sudo ln -s /snap/bin/certbot /usr/bin/certbot

Получаем сертификат:

$ sudo certbot certonly --standalone --agree-tos --no-eff-email --staple-ocsp --preferred-challenges http -m Адрес электронной почты защищен от спам-ботов. Для просмотра адреса в браузере должен быть включен Javascript. -d calibre.example.com

Разберём флаги. Параметр certonly получает только сертификат без автоматической настройки веб-сервера. --standalone запускает временный встроенный веб-сервер для прохождения проверки. --agree-tos автоматически принимает условия использования. --no-eff-email отказывается от рассылки EFF. --staple-ocsp включает OCSP stapling для ускорения проверки сертификата. --preferred-challenges http выбирает HTTP-метод проверки. Параметр -m задаёт email для уведомлений, -d указывает домен.

Поскольку используется standalone-режим, на момент получения сертификата 80-й порт должен быть свободен. На текущем этапе Nginx ещё не запущен, поэтому проблем не будет.

Генерируем параметры Diffie-Hellman:

$ sudo openssl dhparam -dsaparam -out /etc/ssl/certs/dhparam.pem 4096

Параметр -dsaparam ускоряет генерацию для DH-параметров, а размер 4096 бит обеспечивает надёжную криптостойкость. Без флага -dsaparam команда работала бы значительно дольше - иногда десятки минут.

Открываем конфигурацию автообновления сертификата:

$ sudo nano /etc/letsencrypt/renewal/calibre.example.com.conf

Добавляем в конец файла хуки до и после обновления:

pre_hook = systemctl stop nginx
post_hook = systemctl start nginx

Сертификаты Let's Encrypt действуют 90 дней, и обновление происходит через тот же standalone-режим, который требует свободного 80-го порта. Хук pre_hook остановит Nginx перед обновлением, post_hook запустит его обратно. Без этих хуков обновление будет проваливаться, и через три месяца сертификат просто перестанет действовать.

Проверяем работу обновления через сухой запуск:

$ sudo certbot renew --dry-run

Если ошибок нет, всё в порядке. Сертификат будет автоматически продлеваться задолго до истечения срока.

Создание конфигурации виртуального хоста Nginx с проксированием Calibre и поддержкой современных протоколов TLS

Открываем главный конфиг Nginx:

$ sudo nano /etc/nginx/nginx.conf

Перед строкой include /etc/nginx/conf.d/*.conf; добавляем:

server_names_hash_bucket_size 
64;

Этот параметр увеличивает размер хеш-таблицы для хранения имён виртуальных хостов. Без него Nginx может ругнуться при загрузке конфига с длинным доменным именем. Сохраняем файл.

Создаём конфиг для нашего сайта:

$ sudo nano /etc/nginx/conf.d/calibre.conf

Содержимое:

server {
listen 443 ssl http2;
listen [::]:443 ssl http2;

http2_push_preload on; # Enable HTTP/2 Server Push

# Enable TLSv1.3's 0-RTT. Use $ssl_early_data when reverse proxying to
# prevent replay attacks.
#
# @see: https://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_early_data
ssl_early_data on;

server_name calibre.example.com;

client_max_body_size 50M;

access_log 
/var/log/nginx/calibre.access.log;
error_log 
/var/log/nginx/calibre.error.log;

ssl_certificate 
/etc/letsencrypt/live/calibre.example.com/fullchain.pem;
ssl_certificate_key 
/etc/letsencrypt/live/calibre.example.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/calibre.example.com/chain.pem;
ssl_session_timeout 
5m;
ssl_session_cache shared:MozSSL:10m;
ssl_session_tickets off;

ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_ecdh_curve X25519:prime256v1:secp384r1:secp521r1;

ssl_stapling on;
ssl_stapling_verify on;
ssl_dhparam /etc/ssl/certs/dhparam.pem;

location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme; 
}
}

# enforce HTTPS
server {
listen 80;
listen [::]:80;

server_name 
calibre.example.com;
return 301 
https://$host$request_uri;
}

Эта конфигурация заслуживает разбора по частям. Первый блок server отвечает за основной HTTPS-трафик. Параметр listen 443 ssl http2 включает SSL и HTTP/2 - современный протокол, который заметно быстрее HTTP/1.1 за счёт мультиплексирования.

Параметр http2_push_preload on активирует server push - механизм, при котором сервер сам отправляет клиенту ресурсы, которые тот скоро запросит. Опция ssl_early_data on включает поддержку 0-RTT TLS 1.3 - это сокращает задержку при повторных подключениях, что особенно ощутимо на мобильных устройствах с нестабильной сетью.

Параметр client_max_body_size 50M разрешает загрузку файлов до 50 мегабайт - этого достаточно для большинства электронных книг, но при необходимости можно увеличить (например, для скан-копий учебников или альбомов с иллюстрациями).

Блок ssl_* параметров - это набор настроек криптографии. Указаны пути к сертификату и ключу, включены OCSP stapling и кеширование сессий, отключены небезопасные TLS 1.0 и 1.1. Список ssl_ciphers содержит только сильные шифры с прямой секретностью. Параметр ssl_ecdh_curve перечисляет современные эллиптические кривые для ключевого обмена в порядке предпочтения.

Блок location / реализует основное проксирование. Все запросы передаются на 127.0.0.1:8080 - это адрес внутреннего Calibre. Заголовки X-Real-IP и X-Forwarded-For передают исходный IP клиента в Calibre - без них в логах сервиса все запросы выглядели бы как идущие с localhost. Заголовок X-Forwarded-Proto сообщает Calibre, что исходный запрос пришёл по HTTPS, что важно для правильной генерации внутренних ссылок.

Второй блок server слушает 80-й порт и делает безусловный редирект на HTTPS через return 301. Любая попытка зайти по обычному HTTP автоматически перенаправляется на защищённую версию.

Сохраняем файл и проверяем синтаксис:

$ sudo nginx -t

Если ошибок нет, перезапускаем Nginx:

$ sudo systemctl restart nginx

Открываем https://calibre.example.com в браузере - после прохождения базовой авторизации Calibre появляется библиотека со всеми книгами, включая добавленные через cron.

Распространённые подводные камни и практические наблюдения из реальной эксплуатации

В копилку наблюдений из практики стоит добавить несколько моментов, на которых обжигаются те, кто впервые поднимает Calibre Server в боевом окружении.

Первая частая проблема - производительность при больших библиотеках. Calibre великолепно справляется с тысячами книг, но когда коллекция переваливает за десятки тысяч, начинаются заметные задержки при поиске и фильтрации. Лекарство - регулярно запускать calibredb check_library и при необходимости перестраивать индексы через интерфейс. Также имеет смысл хранить базу на SSD-диске, поскольку случайные обращения при поиске метаданных создают много iops.

Вторая популярная грабля связана с правами на каталог watch. Если cron работает от одного пользователя, а файлы в watch-каталог падают от другого (например, через scp с учёткой с другого имени), скрипт может не суметь их удалить, и при следующем запуске они добавятся ещё раз. Получаются дубликаты в библиотеке. Лекарство - либо строго выдерживать единого пользователя для всех источников, либо добавить в crontab логику проверки и обработки ошибок.

Третий момент касается конвертации форматов. Calibre умеет конвертировать книги из одного формата в другой через ebook-convert, и это можно встроить в автоматизацию. Например, при добавлении epub автоматически генерировать mobi для пользователей Kindle. Получается универсальная библиотека, которая отдаёт книгу в нужном формате под конкретное устройство без ручной возни.

Четвёртая тонкость - резервное копирование. Бэкапить нужно сразу две вещи - сам каталог библиотеки (там лежат файлы книг плюс metadata.db с индексом) и каталог .config/calibre с учётными записями пользователей. Без второго при восстановлении придётся пересоздавать всех пользователей, что неудобно при большом числе родственников и друзей с доступом.

Пятый момент - доступ через OPDS. Многие читалки и приложения для электронных книг (Moon+ Reader, KOReader, Foliate, FBReader) умеют подключаться к серверам по протоколу OPDS, что даёт удобный интерфейс прямо на устройстве, без необходимости лезть в браузер. URL для OPDS обычно имеет вид https://calibre.example.com/opds, и его можно сразу прописать в настройках читалки.

Где такая инсталляция пригодится в реальной жизни? Сценариев масса. Личная библиотека для семьи, доступная с любых устройств без облачных сервисов. Корпоративная коллекция технических книг и руководств для команды разработчиков. Библиотека учебных материалов в школе или университете. Архив профессиональной литературы для медиков, юристов, инженеров. Полки специализированной литературы для клубов по интересам - от любителей фантастики до собирателей кулинарных рецептов.

Освоение Calibre Server даёт инженеру не просто навык настройки одного приложения, а целый набор практик работы с веб-сервисами. Связка systemd-юнита, обратного прокси Nginx, TLS-сертификата от Let's Encrypt и cron-автоматизации - это базовый набор для развёртывания практически любого самохостимого проекта. Тот, кто разобрался с Calibre, без труда поднимет Bookstack, Wallabag, Kavita, Komga и другие подобные платформы - принципы у них одинаковые, отличия только в специфике конкретного приложения. Этот сценарий стоит реализовать хотя бы один раз, чтобы перестать зависеть от облачных сервисов в той области, где приватность важнее всего - в собственной коллекции книг и материалов для чтения.