Привет, Хабр! Хочу поделиться немного нетривиальным кейсом по настройке NextCloud в качестве сервиса по созданию защищенных ссылок, для прямого скачивания данных с подключенного сетевого smb\cifs-диска. Опишу решения нюансов, с которыми столкнулся во время настройки.

Зачем это надо?


Удобная доставка контента конечному пользователю, минуя возню с FTP и невозможность (из-за NDA) воспользоваться публичными сервисами и облаками для передачи файлов (BTsync, Google-\Mail-\Yandex-Disk\Dropbox\etc).





Предисловие


Наш офис имеет определенную инфраструктуру, в неё входит в том числе и ActiveDirectory, в которой у нас находятся сотрудники, состоящие в группах.

Во время сеанса работы за ПК, после логина, средствами настроенных политик, у каждого сотрудника монтируется сетевой диск. Через него время-от-времени идет обмен данными. В диске есть определенная структура папок, права на которые настроены через эти самые группы. Каждый видит то, что ему позволено настройками.

Обычно, для отдачи данных во внешний мир — поднимается, либо отдельный FTP, либо данные выгружаются на уже имеющийся. Признаюсь, это далеко не всегда удобно — как минимум, создание и управление временными логинами и паролями (например, когда партнёрам нужно отдать готовый контент), контроль места на FTP-сервере, ручная выгрузка на FTP-сервер перед “отправкой”.

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

На такую идею нас натолкнули одни из партнеров, так как у них имелся внутренний сервис, но там он был самописным.

Готовых вариантов с ходу в поисковике не нашлось (если у вас есть оные на примете — отпишитесь, пожалуйста в комментариях), а тратить потенциально много человеко-часов на разработку с нуля, тестирование и поддержку — не было желания и ресурсов ни у кого. Да и зачем изобретать велосипед, если зачастую все уже придумано до. Так на ум и пришел сервис NextCloud, который умеет подключать к себе внешние ресурсы.

Речь пойдет о последней стабильной, на данный момент версии — 19, но наш метод настройки подойдет и для более ранних версий — мы изначально реализовали это на 16 версии и потом постепенно обновлялись. Недавно я как раз поднимал его с нуля на последней (19), и опираясь на неё пишу статью.

Что мы хотим получить в конечном итоге:


  • Только сотрудники могут заходить в наш сервис и только через ActiveDirectoty\LDAP, точно так же как заходят на офисный пк, в Jira, Confluence, Nexus и пр.
  • После авторизации в веб интерфейсе NextCloud, сотруднику должен быть подключен наш сетевой диск, с точно такими-же правами, как это происходит при заходе с рабочего компьютера.
  • При первом входе в NextCloud — у каждой учетной записи создаются файлы-примеры в домашнем каталоге, которые занимают места на диске. По хорошему, от этого надо избавиться.
  • Сотрудник не должен иметь возможность загружать что либо, как на подключенный диск, так и в аккаунт NextCloud .*Это просто наша хотелка, на самом деле — она не обязательная.
  • Сотрудник может создавать временные ссылки, защищенные паролем на любые доступные ему ресурсы — будь то папка или отдельный файл. А также управлять ими (ссылками) — отзывать, менять срок жизни и прочее.
  • Конечному пользователю, кому отправлена защищенная ссылка, достаточно её открыть и ввести пароль, чтобы получить возможность скачать расшаренные ему данные.



Развёртка и настройка зависимостей


Для начала, нам надо иметь отдельную виртуалку или сервер, где можно установить операционную систему, и после — NextCloud.

На Хабре есть не одна статья, посвященная развёртке системы и сервиса.

AlexanderS достаточно хорошо и подробно описал процесс от установки системы до самой настройки облака (включая актуализацию статей по годам). Не вижу смысла в очередной раз это всё повторять.

1. Так как мы подключаем в NextCloud сетевой диск, то нам понадобятся пакеты в систему: smbclient, libsmbclient , php-ldap, и php-smbclient.

Ремарка, на случай использования Docker
Если вы тоже используете докер, то напомню — официальный образ не имеет на борту пакетов для работы с samba и вам лучше создать форк, установив их в своем Dockerfile. И, согласно документации, установка пакета php-smbclient внутри их образа немного отличается от классического “apt install package”.

Пример Dockerfile
FROM nextcloud:latest
RUN apt update -y &&  apt install -y --allow-unauthenticated smbclient libsmbclient libsmbclient-dev
RUN pecl install smbclient
RUN docker-php-ext-enable smbclient



2. Из-за особенностей настроек нашего сервера samba (отключена поддержка smb1), на машине с nextcloud, в файлах /etc/samba/smb.conf и /usr/share/samba/smb.conf пришлось поменять строки, отвечающие за протокол:

[global] 
client min protocol = SMB2
client max protocol = SMB3

Продолжение примера Dockerfile
RUN rm -frv /etc/samba/smb.conf /usr/share/samba/smb.conf
ADD smb.conf /etc/samba/
ADD smb.conf /usr/share/samba/


В ином случае, nextcloud так и не смог подключиться к диску.



Настройка nextcloud


Итак, Nextcloud уже установлен, зависимости поставлены, а в сервисе заведен один внутренний юзер, который создался во время установки.

Шаг первый. Подготовка шаблона аккаунтов сотрудников.


Поскольку у нас будет не один сотрудник в системе, а постепенно их количество будет меняться — если заранее не настроить шаблон создаваемого пользователя — у каждого будет в домашней папке несколько файлов-примеров. Хорошо что по этому поводу у nextcloud есть отдельная настройка — skeleton files, которая настраивается в config.php.

  'skeletondirectory' => '/var/www/html/data/donotdeletme',

То есть, можно создать пустую папку и указать в конфиге полный путь к ней.

Шаг Второй. Делаем пользователей «read-only»


Достаточно указать квоту в «1 B» (1 байт) в разделе настроек пользователей (http(s)://nextcloud.domain.tld/settings/users).

Шаг третий — заранее чиним ZipStreamer


ZipStreamer — библиотека, используемая в бекенде NextCloud, она служит для создания архивов «на лету», то есть во время скачивания пачки файлов.



Как это работает
Если вы перейдя по шареной ссылке, нажали кнопку "Dowload All Files"/"Скачать все файлы", то вы заметите, что вам не показывается в браузере (или в менеджере загрузок) конечный вес архива, а полоса загрузки будет неопределенной.



Это связано с тем, что по этой кнопке система в режиме реального времени создает и отдает вам на скачивание архив (в большинстве случаев .zip, в редких кейсах — .tar)

Кстати, в силу особенности этой технологии, возобновление приостановленных загрузок в этом случае невозможно.

Похожее поведение есть у и аналогичных сервисов: Google Drive, Яндекс.Диск, и т.д.

Проблема кроется в том, что по неизвестным причинам, заложенная в NextCloud логика переключения zip в zip64 сбоит, и при случае, если в папке больше 65536 файлов, и\или их общий вес будет превышать 4гб — скорее всего вы столкнетесь с проблемой, что скачанный файл будет либо побит, либо загрузка будет прерываться после скачанных 4гб.

Данной проблеме выделяли достаточное время, на GitHub даже есть, и не один, закрытый тикет (#1755, #15871, #8798), но несмотря на то, что якобы проблема решена — у нас она так и осталась, и с переменным успехом воспроизводилась, очень мешая работе. Пришлось решать её более радикально.

Решение
Поскольку у нас 100% 64хбитная система, то мы принудительно говорим библиотеке использовать 64х-битный режим. «Решение в лоб».

<папка, где установлен nextcloud>/lib/private/Streamer.php:
- $this->streamerInstance = new ZipStreamer(['zip64' => false]);
+ $this->streamerInstance = new ZipStreamer(['zip64' => true]);

Ремарка, на случай использования Docker
В официальном образе происходит при каждом запуске контейнера некий Integrity Check и из одного места в другое распаковываются оригинальные файлы поверх установленных( из /usr/src/nextcloud/* в /var/www/html/*).

Поэтому просто в лоб замапить файл в условном /var/www не получится — при запуске файл либо перетрется оригиналом, либо контейнер запустится и упадет сразу с ошибкой.

Так что мы подменяем патченым файлом исходный в папке /usr/src/nextcloud/lib/private/ еще при сборке в CI нашего форкнутого образа. Получается, наш поправленный файл будет гарантированно всегда использоваться.

Продолжение примера Dockerfile
RUN rm -frv /usr/src/nextcloud/lib/private/Streamer.php
ADD Streamer.php /usr/src/nextcloud/lib/private/
RUN chown nobody:nogroup /usr/src/nextcloud/lib/private/Streamer.php

Эти манипуляции, по крайней мере при использовании докер-образа, в Панели Администрирования точно завалят вам встроенную проверку на подлинность, имейте это ввиду.




Но лично нас пока это устроило.

Шаг четвертый — настраиваем параметры ссылок


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

Шаг пятый — подключаем сетевой диск


  1. Переходим в настройку внешних хранилищ. (http(s)://nextcloud.domain.tld/settings/admin/externalstorages)
  2. Выбираем добавление SMB \ CIFS хранилища.
  3. Заполняем поля имени, домена, папки и тд.
  4. Выбираем «Учетные данные, хранить в базе данных» — именно этот пункт позволяет при заходе пользователя по его связке логина и пароля подключать диск к его учетной записи в NextCloud. (Пункт хранение логина и пароля во время сессии не взлетел).
  5. Не забываем в меню <...> отметить чекбоксами «Только чтение» и разрешение предоставление общего доступа.

Шаг шестой — запускаем пользователей через LDAP


Теперь, когда мы все подготовили — ставим из маркетплейса плагин, и сразу после подключаем LDAP. В нашей системе, мы давали доступ сотрудникам, которые находятся в группе NextcloudAccess. Можете сделать аналогично.



Заключение


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

Полный пример нашего Dockerfile
FROM nextcloud:latest
ENV DEBIAN_FRONTEND noninteractive

#installing smbclient
RUN apt update -y &&  apt install -y --allow-unauthenticated smbclient libsmbclient libsmbclient-dev
RUN pecl install smbclient
RUN docker-php-ext-enable smbclient

#fix of ZipStreammer
RUN rm -frv /usr/src/nextcloud/lib/private/Streamer.php
ADD Streamer.php /usr/src/nextcloud/lib/private/
RUN chown nobody:nogroup /usr/src/nextcloud/lib/private/Streamer.php

#fix of smb config
RUN rm -frv /etc/samba/smb.conf /usr/share/samba/smb.conf
ADD smb.conf /etc/samba/
ADD smb.conf /usr/share/samba/




Нагрузочное тестирование


«Как дела с нагрузкой?» — спросите вы напоследок.

Замеры в час пик




Наш инстанс сервиса крутится на ~ 6Gb Ram + 6CPU в виртуальной машине среди других VM.

При пике нагрузки на сеть — оперативной памяти использовалось чуть более 2.5Gb, процессор забит не был, а отдача в среднем была около 5Gbit/s (рекорд — доходило и до 8Gbit/s).

Единственное, что заметили — при отдаче сверх 6Gbit/s во внешний мир, у нас периодически отваливается web-интерфейс, но сами загрузки у пользователей продолжают идти.


Выявленные недостатки:


  • В NextCloud нету возможности глобального контроля над всеми созданными ссылками. Они отображаются только внутри каждого аккаунта в отдельном разделе.
  • Если вы расшарите по ссылке корень подключенного диска — это может служить потенциальной утечкой данных, так как в ссылке расшарятся все доступные вашему аккаунту папки.
  • Заметил, что за год использования поднятого сервиса, на данный момент, в базе данных таблица oc_filecache весит ~29Gb и имеет около ~100кк строк (мы используем ванильную MySQL 5.7.x). Это связано с багами #16834, #6395, #7312, #20349. Пока идет наблюдение на втором инстансе.



Спасибо, что дочитали. Если у вас есть вопросы, замечания или пожелания — не стесняйтесь, всегда рад конструктивной критике.



Проверено на: nextcloud 16, 17, 18, 19
Дата написания: 26.07.2020
Дата правок: 05.08.2020
Что поправлено: Поправил формулировку о режиме работы zip\zip64.
Версия: 1.0.0.8