У будь-якому офісі щодня треба щось зробити з PDF: зшити кілька сканів у один файл, стиснути важкий документ, щоб проліз у пошту, перегнати Word чи Excel у PDF перед відправкою, зняти пароль зі звіту, розпізнати текст у скані. І майже завжди це закінчується однаково - людина забиває в пошук «merge pdf online», тягне файл на перший-ліпший сайт і тисне кнопку. А в тому файлі - договір, виписка з банку чи персональні дані клієнтів, які щойно поїхали на невідомий сервер у невідомій юрисдикції.
Stirling PDF закриває цю діру одним рухом: це веб-набір інструментів для PDF, який ти ставиш на власну машину. Об’єднання, розбиття, стиснення, конвертація Office<->PDF, OCR, підписи, додавання й зняття паролів, поворот сторінок - десятки операцій, і всі вони виконуються на твоєму сервері. Файли нікуди не їдуть. Для офісу це ідеальний варіант: один контейнер, веб-інтерфейс, а в третій версії вхід захищений паролем уже з коробки, тож сервіс не стоїть нарозхрист для всієї локальної мережі.
Це другий пост серії «Офіс без адміна»: ставимо корисні сервіси так, щоб їх потягнула людина без фаху системного адміністратора. У першому ми підняли власний сейф для паролів на Vaultwarden. Сьогодні - власний PDF-комбайн, від порожньої VM до працюючого інструмента в браузері.
Що потрібно зробити?#
Підняти Stirling PDF на одній віртуалці для офісу приблизно на 20 людей:
- винести дані (конфіги, базу користувачів, мовні дані OCR) на окремий диск - щоб бекапити й переносити їх окремо від системи;
- поставити Docker і запустити зв’язку Stirling PDF + Caddy одним
docker compose; - узяти правильний образ - той, що вміє конвертувати кириличні документи й розпізнавати текст, а не урізаний;
- докинути українські мовні дані для OCR;
- зробити HTTPS без публічного домену через внутрішній центр сертифікації Caddy;
- насамкінець замкнути двері - змінити типовий пароль адміна, щоб сервіс не був відкритий для всіх.
З чим працюю?#
Stirling PDF - це не Vaultwarden. Повний образ тягне за собою LibreOffice для конвертації Office-документів і рушій OCR, тож і апетити в нього більші. Будьмо чесними: реалістичний мінімум - 2 vCPU / 4 ГБ RAM, комфортно - 4 vCPU / 8 ГБ. У простої сервіс їсть близько 1.3 ГБ пам’яті, а під час OCR може стрибнути до ~2 ГБ.
Я розгортав на такій машині:
- 4 vCPU, 6 ГБ RAM;
- 12 ГБ системного диска + окремий 4 ГБ диск під дані;
- ОС Ubuntu 26.04 LTS;
- плюс 2 ГБ swap - дешева страховка на піки OCR.
Сервер у прикладі доступний у локальній мережі за адресою 192.168.1.51 - публічного домену в нас поки немає. Усюди далі підставляй свою адресу.
Окремий диск під дані#
Логіка та сама, що й у пості про Vaultwarden: дані не повинні лежати там само, де система. У Stirling PDF на окремий диск ми винесемо конфіги, базу з користувачами й паролями та мовні дані OCR - усе, що боляче втратити при переставлянні системи. Тому під сервіс ми й підкинули віртуалці другий диск на 4 ГБ.
У системі він з’являється порожнім пристроєм /dev/sdb. Форматуємо його в ext4 з міткою spdfdata й монтуємо:
| |
Щоб диск підмонтувався сам після перезавантаження, додаємо його в /etc/fstab по UUID (імена пристроїв можуть помінятися місцями). UUID підкаже blkid:
| |
Рядок у /etc/fstab (підстав свій UUID):
| |
Перевіряємо запис, одразу монтуючи все з fstab:
| |
Якщо команда відпрацювала без помилок і /mnt/data змонтувався - диск готовий і переживе перезавантаження.
Поки ми тут, додамо обіцяні 2 ГБ swap - саме задля пікових OCR-операцій:
| |
І теж закріплюємо в /etc/fstab, щоб swap вмикався сам:
| |
Докладніше про те, навіщо окремий диск і як це рятує при переносі, розписано в пості про Vaultwarden - тут я свідомо стисло.
Docker з репозиторіїв Ubuntu#
Stirling PDF ми запустимо в контейнері. Як і минулого разу, нам не потрібен окремий офіційний репозиторій Docker: у штатних репозиторіях Ubuntu 26.04 лежить цілком свіжий. Ставимо двома пакетами:
| |
Це дає Docker 29.x і сучасний docker compose версії 2.40.x (саме docker compose, двома словами). Більше нічого підключати не треба.
Який образ брати: чому саме fat#
А тут - головна розвилка, на якій легко зробити помилку й потім довго дивуватися, «чому не працює». У Stirling PDF є три варіанти образу:
ultra-lite- лише базові операції. Без OCR, без конвертації Office-документів, без входу з паролем. Виглядає спокусливо «легким», але для офісу це пастка.- стандартний (
latest) - майже все, окрім частини важких залежностей. fat- повний комплект: LibreOffice для конвертації, OCR і, що критично, вшиті шрифти.
Для офісу, якому треба перетворювати на PDF кириличні документи, вибір однозначний - fat. Саме повний образ несе в собі шрифти, завдяки яким українські .docx і .xlsx конвертуються правильно, а не перетворюються на квадратики. Плюс до цього - OCR і LibreOffice. ultra-lite для такої задачі брати не можна: ні OCR, ні конвертації Office, ні навіть входу.
Ще один важливий момент - ім’я образу. Старе frooodle/s-pdf уже застаріле. Актуальний образ тягнемо звідси:
| |
Stirling PDF і Caddy одним compose-файлом#
Складемо весь сервіс в одній папці /opt/stirling. Stirling ми не публікуємо на хост напряму - його прикриє Caddy, який проксуватиме запити всередині мережі compose, а назовні віддаватиме HTTPS.
| |
Ось docker-compose.yml:
| |
Розберемо, що тут важливо:
SECURITY_ENABLELOGIN: "true"- вмикаємо вхід із паролем. У третій версії для не-ultra-liteобразів він і так увімкнений за замовчуванням, але краще сказати це явно.SECURITY_INITIALLOGIN_USERNAME/SECURITY_INITIALLOGIN_PASSWORDзадають першого адміністратора. Є нюанс, про який нижче: ці змінні спрацьовують лише на найпершому запуску, поки ще не створено базу користувачів у/configs.SYSTEM_DEFAULTLOCALE: "uk-UA"- українська мова інтерфейсу за замовчуванням.JAVA_TOOL_OPTIONS: "-Xms512m -Xmx2500m"- рамки для Java: з чого стартувати й куди не виходити по пам’яті.PROCESS_EXECUTOR_...LIBRE_OFFICE_SESSION_LIMIT: "1"- дозволяємо LibreOffice лише одну конвертацію за раз, щоб не з’їсти всю пам’ять на пачці документів.- Усі томи ведуть на наш окремий диск
/mnt/data/stirling/*. Окремо зверни увагу наtessdata- про нього наступний розділ. deploy.resources.limitsставить стелю: 4 ГБ пам’яті й 4 ядра, щоб сервіс не поклав усю машину.
Caddy тут такий самий, як у пості про Vaultwarden: приймає HTTPS і передає запити Stirling’у.
Українська мова для OCR#
Повний образ приходить із мовними даними для OCR тільки на англійську. Але є тонкість: ми змонтували власний том у /usr/share/tessdata, а том перекриває те, що вшите в образ. Тобто якщо просто лишити теку порожньою, OCR узагалі не матиме мов. Тому в неї треба покласти і англійську, і українську руками.
Качаємо дані в /mnt/data/stirling/tessdata:
| |
Ми беремо tessdata_fast - це менші й швидші моделі. Якщо захочеш точнішого розпізнавання ціною швидкості, є tessdata_best.
Два правила, щоб потім не ловити сюрпризів: ніколи не видаляй eng (без англійської частина сценаріїв ламається), і том tessdata має бути постійним - якщо він пропаде при переставлянні, мови зникнуть разом із ним.
Caddyfile: HTTPS без домену#
HTTPS робимо так само, як у пості про Vaultwarden - через внутрішній центр сертифікації Caddy, бо публічного домену в нас немає. Внутрішній порт Stirling PDF - 8080, саме на нього Caddy і проксує:
| |
tls internal каже Caddy стати власним CA, а default_sni потрібен, бо при зверненні по IP клієнт не надсилає імені сервера, і без цього рядка TLS-рукостискання обривається.
Приємна відмінність від минулого разу: у Caddy немає типового обмеження на розмір тіла запиту, тож навіть великі PDF завантажуються без зайвих налаштувань. Якби замість Caddy стояв nginx, довелося б окремо піднімати client_max_body_size - а тут нічого не треба.
Запускаємо все:
| |
Роздаємо довіру#
Компроміс життя без домену той самий: сертифікат видав наш власний CA, якого браузери поки не знають. Кореневий сертифікат Caddy лежить тут:
| |
Цей root.crt треба раз установити на офісні пристрої в довірені - як саме для Linux, Windows, macOS і мобільних, докладно розписано в пості про Vaultwarden. Перевірити, що сервер відповідає по HTTPS, можна одразу, вказавши curl наш кореневий сертифікат:
| |
У відповідь прилетить код 200 - сервер живий.
Що воно вміє#
Тепер найприємніше - заради чого все й затівалося. Відкриваємо https://192.168.1.51/, входимо й бачимо головну: десятки інструментів, розкладених по групах.

Чотири сценарії, які в офісі трапляються щодня:
- Об’єднати кілька PDF в один. Класика: три скани договору зшити в один файл перед відправкою. Кидаєш файли, розставляєш порядок - отримуєш один PDF.
- Стиснути важкий PDF. Документ на 40 МБ не лізе в пошту - проганяєш через стиснення й отримуєш файл, який спокійно йде листом.
- Конвертувати український Word чи Excel у PDF. Ось тут і окупається fat-образ: кириличний
.docxчи.xlsxперетворюється на PDF із правильними літерами, а не квадратиками, бо потрібні шрифти вже всередині. - Розпізнати текст у скані (OCR). Сканований український документ, по якому не можна шукати й копіювати, прогониш через OCR - і на виході маєш PDF, у якому текст виділяється й шукається.
Усе це - у браузері, кількома кліками, і жоден файл не покидає сервера:
Замикаємо двері#
Найважливіше для офісного сервісу - щоб ним не скористався хто завгодно з мережі. У третій версії Stirling PDF вхід із паролем для нашого образу увімкнений за замовчуванням, і це добре. Але є дві речі, які треба зробити руками.
По-перше, типовий пароль. Якщо не задати свій, Stirling стартує з парою admin / stirling і сам змусить змінити пароль на першому вході. Не лишай його типовим: або задай свій одразу через SECURITY_INITIALLOGIN_PASSWORD, або зміни при першому вході.
По-друге, важливий нюанс із тими змінними. SECURITY_INITIALLOGIN_USERNAME і SECURITY_INITIALLOGIN_PASSWORD задають першого адміна лише на найпершому запуску - поки ще не створено базу користувачів (вона лягає в /configs). Після першого старту ці змінні вже нічого не змінюють: далі користувачами й паролями керуєш в інтерфейсі, у розділі Admin -> user management. Тобто дописати нового співробітника через зміну compose-файлу не вийде - це робиться в веб-інтерфейсі.
Є ще й повноцінний вхід через зовнішнього провайдера (SSO / OAuth2 - Keycloak, Authentik, Authelia, Google), і в третій версії він безкоштовний. Але для офісу без адміна це надмір: звичайного входу з паролем цілком достатньо, а SSO варто чіпати лише тоді, коли в компанії вже є централізований вхід, до якого хочеться це причепити.
Заковики, які варто знати#
Дві речі, через які в новачків «не працює»:
ultra-lite- пастка. Він легший, але без OCR, без конвертації Office і навіть без входу. Для офісу бериfat- інакше половина сценаріїв просто відсутня, а кирилиця в конвертації перетвориться на квадратики.- Не видаляй
engізtessdata. Томtessdataперекриває вшиті в образ мови, тож туди мусять лежати і англійська, і українська. Прибереш англійську - частина сценаріїв відвалиться. І сам том має бути постійним, інакше мови зникнуть при переставлянні.
Куди далі#
Маємо власний PDF-комбайн: один раз розгорнули - і офіс перестав носити договори та виписки на випадкові онлайн-сайти. Наступні кроки, коли буде настрій: SMTP, щоб користувачі могли відновлювати пароль листом, і SSO, якщо в компанії вже є централізований вхід.
Якщо ж уся ця історія з «зроби сам» - не твоє, і хочеться, щоб хтось просто розгорнув і наглядав за цим замість тебе, напиши в teneta.tech - підкажуть і візьмуть на себе.
А серію «Офіс без адміна» продовжимо: цеглинка за цеглинкою зберемо офісну інфраструктуру, яку потягне звичайна людина без системного адміністратора за плечима.



