====== Nextcloud ====== По ходу инсталляции, будут настроены "pretty URLs" (ссылки без index.php в составе), кэш и настройка аутентификации через LDAP. Fail2ban (утилита против брутфорса) рассматривается [[Fail2ban|в отдельной статье]]. ===== Установка и настройка системы и необходимых компонентов ===== Во время установки Ubuntu Server, отметить для установки SSH Server и LAMP. Выбрать автоустановку обновлений безопасности. # Войти в режим рута sudo -i # Задать статический IP: nano /etc/network/interfaces auto eth0 iface eth0 inet static address 192.168.1.7 netmask 255.255.255.0 gateway 192.168.1.1 dns-nameservers 192.168.1.1 dns-search workgroup Перезагрузиться. Зайти в систему по SSH и обновить систему целиком: sudo -i apt-get update && apt-get upgrade -y && apt-get dist-upgrade -y && apt-get autoremove Установить все необходимые компоненты и, в данном случае, [[https://docs.nextcloud.com/server/11/admin_manual/configuration_server/caching_configuration.html|механизм кэширования APCu + Redis]] и [[https://docs.nextcloud.com/server/12/admin_manual/configuration_server/theming.html#theming-of-icons|компоненты для автогенерации favicon]]: apt-get install php-zip php-xml php-gd php-json php-curl php-mbstring php-bz2 php-intl php-mcrypt php-apcu redis-server php-redis php-imagick libmagickcore-6.q16-6-extra -y # Обновление PHP на 8.2 apt install php8.2 php8.2-fpm php8.2-bcmath php8.2-bz2 php8.2-curl php8.2-gd php8.2-gmp php8.2-igbinary php8.2-imagick \ php8.2-intl php8.2-ldap php8.2-mbstring php8.2-mcrypt php8.2-mysql php8.2-redis php8.2-simplexml php8.2-smbclient php8.2-xml php8.2-xsl php8.2-zip Если нужен SMB client (для подключения внешних накопителей в Nextcloud), LDAP и Midnight Commander: apt-get install smbclient php-ldap mc -y ===== Клиент ===== https://nextcloud.com/install/#install-clients # WebDAV https://bva.dyndns.info/cloud/remote.php/dav/files/ ===== Установка Nextcloud ===== # Скачать последнюю версию wget https://download.nextcloud.com/server/releases/latest.tar.bz2 # Распаковать архив в корневую папку веб-сервера tar xjf latest.tar.bz2 --strip=1 -C /var/www/html # Удалить исходный архив (если нужно) rm latest.tar.bz2 # Создать папку для пользовательских данных mkdir /var/nextcloud-data # Дать права владельца веб-серверу: chown -R www-data:www-data /var/www/html /var/nextcloud-data # Перезапустить Apache: systemctl restart apache2 # Создать базу MySQL с именем "nextcloud": mysql -u root -p -e "create database nextcloud"; Открыть браузер, зайти на веб-интерфейс (здесь: 192.168.1.7), задать логин и пароль админа, путь к папке с данными пользователей (здесь: /var/nextcloud-data) и имя БД (здесь: nextcloud). Либо [[https://docs.nextcloud.com/server/12/admin_manual/configuration_server/occ_command.html#command-line-installation-label|настроить из командной строки]]:\\ FIXME - уточнить, можно ли тут обойтись без паролей sudo -u www-data php /var/www/html/occ maintenance:install --database "mysql" --data-dir "/var/nextcloud-data" --database-name "nextcloud" --database-user "root" --database-pass "password" --admin-user "admin" --admin-pass "password" ===== Настройка ===== # Убрать закрывающую строку из конфига и заменить строку overwrite.cli.url на нужную. # В sed экранирование апострофа безумное - '"'"' sed -i ' /);/d /overwrite.cli.url/c \'"'"'overwrite.cli.url\'"'"' => \'"'"'https://192.168.1.7\'"'"',' /var/www/html/config/config.php # Настроить конфиг - "pretty URLs", кэширование, часовой пояс для логов и их ротацию (100 МБ) echo "'htaccess.RewriteBase' => '/', 'memcache.local' => '\OC\Memcache\APCu', 'memcache.locking' => '\OC\Memcache\Redis', 'redis' => array( 'host' => 'localhost', 'port' => 6379, ), 'logtimezone' => 'Europe/Moscow', 'log_rotate_size' => 104857600, );" >> /var/www/html/config/config.php # Настроить максимальный размер файла на закачку в PHP и лимит памяти # Проверить версию PHP и путь к используемым php.ini (php --ini), например, он может быть # /etc/php/7.3/fpm/php.ini. Есть ещё # /etc/php/7.3/cli/php.ini. sed -i ' /upload_max_filesize =/c upload_max_filesize = 4G /post_max_size =/c post_max_size = 4G /memory_limit =/c memory_limit = 512M' /etc/php82/php.ini # Настроить параметры opcache sed -i ' /opcache.enable=/c opcache.enable=1 /opcache.enable_cli=/c opcache.enable_cli=1 /opcache.memory_consumption=/c opcache.memory_consumption=128 /opcache.interned_strings_buffer=/c opcache.interned_strings_buffer=8 /opcache.max_accelerated_files=/c opcache.max_accelerated_files=10000 /opcache.revalidate_freq=/c opcache.revalidate_freq=1 /opcache.save_comments=/c opcache.save_comments=1 /opcache.interned_strings_buffer=/c opcache.interned_strings_buffer=16 ' /etc/php82/php.ini [[http://php.net/manual/en/timezones.php|Список часовых поясов для PHP]] ==== SSL, mod_env и mod_rewrite для pretty URLs ==== a2enmod ssl headers env rewrite && a2ensite default-ssl Включить Strict transport security, [[https://www.w3.org/TR/referrer-policy/|Referrer Policy]] и Forward secrecy: echo " Header always set Strict-Transport-Security "max-age=15768000; includeSubDomains" Header always set Referrer-Policy "no-referrer-when-downgrade" # Set Forward Secrecy SSLProtocol all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1 SSLHonorCipherOrder on SSLCipherSuite HIGH:!aNULL:!MD5:!3DES " >> /etc/apache2/sites-available/default-ssl.conf ==== Перенаправить HTTP на HTTPS ==== nano /etc/apache2/sites-available/000-default.conf ServerName www.yourdomain.com Redirect / https://www.yourdomain.com/ systemctl restart apache2 ==== Настроить Pretty URLs ==== nano /etc/apache2/apache2.conf # В разделе изменить параметр AllowOverride None на AllowOverride All # Выйти из редактора. # Обновить файл .htaccess: sudo -u www-data php /var/www/html/occ maintenance:update:htaccess # Перезапустить Apache: systemctl restart apache2 ==== Переключить фоновые задачи на выполнение кроном ==== echo "# Nextcloud cron schedule" >> /etc/crontab echo "*/15 * * * * www-data php -f /var/www/html/cron.php" >> /etc/crontab sudo -u www-data php /var/www/html/occ background:cron https://docs.nextcloud.com/server/13/admin_manual/configuration_server/background_jobs_configuration.html ==== Выключить ненужные ссылки ==== config/config.php: # Выключить ссылку на сброс пароля 'lost_password_link' => 'disabled', # Remove link “Get your own free account” 'simpleSignUpLink.shown' => false, ==== Настроить аутентификацию через LDAP ==== Для работы этого типа аутентификации необходимо установить компонент php-ldap, если он не был установлен ранее: apt-get install php-ldap -y ++++Далее настройка производится в веб-интерфейсе админа. | Прописать адрес контроллера домена, пользователя, который ходит за учётками в AD, и подразделение, из которого берутся пользователи. Здесь это корень домена, но можно указать, к примеру, корневое подразделение организации, чтобы ограничить область поиска.\\ {{:nextcloud-settings-ldap-server.png?400|}} Выборку критериев отбора объектов лучше всего прописывать вручную - в этом случае отключенные в AD пользователи исчезнут и из пользователей Nextcloud. Вот эта строка: (&(&(objectclass=user)(objectcategory=person))(!(userAccountControl:1.2.840.113556.1.4.803:=2))) {{:nextcloud-settings-ldap-users.png?400|}} Вкладка Advanced - Connection settings: прописать запасной контроллер домена.\\ {{:nextcloud-settings-ldap-adv-conn-set.png?400|}} Вкладка Advanced - Directory settings: указать, как показывать имена пользователей и групп в интерфейсе. По умолчанию пользователи показываются в виде их UUID, что совершенно неприемлемо. Также нужно прописать пути к корневому подразделению организации. Нижнему параметру выставить значение member (AD).\\ {{:nextcloud-settings-ldap-adv-dir-set.png?400|}} Вкладка Advanced - Special attributes: задаём, откуда брать почтовый адрес пользователя и критерий именования личного каталога пользователя на сервере. Почтовый адрес нужен, чтобы можно было слать уведомления о появлении общих ресурсов прямо из интерфейса, не копируя ссылку. Для этого необходимо заполнить поле почтового адреса в AD у всех пользователей. Личный каталог пользователя по умолчанию именуется значением UUID. Гораздо лучше, если папка будет называться соответственно логину.\\ {{:nextcloud-settings-ldap-adv-spec-attr.png?400|}} Вкладка Expert: задать внутреннее имя пользователя как логин в AD вместо неудобоваримого UUID.\\ {{:nextcloud-settings-ldap-expert.png?400|}}++++ ==== Онлайн-офис ==== # Collabora (довольно тормозной вариант) sudo -u www-data php /var/www/html/occ app:install richdocumentscode richdocuments # OnlyOffice (ограничение в 20 соединений в бесплатной версии) sudo -u www-data php /var/www/html/occ app:install documentserver_community onlyoffice Для OnlyOffice, добавить в ''/var/www/html/config/config.php'': 'onlyoffice' => array ( 'verify_peer_off' => true, ), 'allow_local_remote_servers' => true, OnlyOffice - работа через прокси: https://helpcenter.onlyoffice.com/ru/installation/docs-community-proxy.aspx "Неизвестная ошибка" при открытии документа - нужно в конфиге Nextcloud 'overwriteprotocol' => 'https', (add) 'overwrite.cli.url' => 'https' (change) https://github.com/nextcloud/docker/issues/975 ==== Внешние хранилища ==== === S3 === Способ доступа - Access key\\ Bucket - каталог в облаке, например, Media\\ Hostname - s3.cloud.mts.ru\\ Port - 443\\ Region - пусто\\ ✔ Enable SSL\\ ✔ Enable path style === SMB (CIFS) === Host - [IP address]\\ Share - Files (имя общего ресурса)\\ Remote subfolder - Отдел продаж\Группа впаривания\Обмен\\ Domain - example.com ===== Обновление ===== # Автоматически: sudo -u www-data php /var/www/html/updater/updater.phar # Вручную: # Скачать последний релиз wget https://download.nextcloud.com/server/releases/latest.tar.bz2 # Распаковать скачанный архив в папку установки tar xjf latest.tar.bz2 --strip=1 -C /var/www/html # Дать права владельца веб-серверу: chown -R www-data:www-data /var/www/html # Включить режим обслуживания sudo -u www-data php /var/www/html/occ maintenance:mode --on # Запустить процесс обновления sudo -u www-data php /var/www/html/occ upgrade # Выключить режим обслуживания sudo -u www-data php /var/www/html/occ maintenance:mode --off https://docs.nextcloud.com/server/latest/admin_manual/maintenance/update.html Экспресс-обновление со сменой шлюза ip route change default via 192.168.1.254 dev eth0 apt update && apt upgrade -y && apt autoremove -y sudo -u www-data php /var/www/html/updater/updater.phar --no-interaction ip route change default via 192.168.1.1 dev eth0 Обновление на след. мажорный релиз # Нужно переключиться на бета-канал обновлений, обновляться, а затем переключиться обратно. sudo -u www-data php /var/www/html/cloud/occ config:system:set updater.release.channel --value=beta sudo -u www-data php /var/www/html/cloud/updater/updater.phar --no-interaction sudo -u www-data php /var/www/html/cloud/occ config:system:set updater.release.channel --value=stable В Докере docker exec nc-php sudo -u www-data php /var/www/html/cloud/occ config:system:set updater.release.channel --value=beta docker exec nc-php sudo -u www-data php /var/www/html/cloud/updater/updater.phar --no-interaction docker exec nc-php sudo -u www-data php /var/www/html/cloud/occ config:system:set updater.release.channel --value=stable ==== Обновление всех приложений ==== sudo -u www-data php /var/www/html/cloud/occ app:update --all # docker docker exec -uwww-data nc-php php /var/www/html/cloud/occ app:update --all ===== Настройка кэширования через сервер Redis ===== Как-то раз произошла ситуация - невозможно было стереть файл с сервера или обновить его, файл был заблокирован: file is locked\\ Error transferring bva.dyndns.info/cloud/remote.php/dav/files/user/123.txt - server replied: Locked ("123.txt" is locked) [[https://help.nextcloud.com/t/file-is-locked-how-to-unlock/1883|В соответствующем howto]] советуют обнулить таблицу блокировок в базе mysql, а чтобы ситуация не повторялась, рекомендуют [[https://docs.nextcloud.com/server/12.0/admin_manual/configuration_server/caching_configuration.html#id3|поставить кэширующий сервис Redis]]. Так как у меня уже был APCu, было решено поставить Redis для блокировок, а APCu оставить для локального кэша. В Ubuntu это ставится просто, а в Armbian в репозитории отсутствуют соответствующие пакеты, так что пришлось их собирать из исходников. ==== Установить Redis ==== Информация устарела, в репозиториях для процессоров ARM появились собранные пакеты.\\ Теперь достаточно выполнить команду\\ apt-get install redis-server php-redis ++++ Сборка из исходников | # Установить пакет tcl для возможности протестировать инсталлятор после сборки, возможно, он не нужен, т. к. тестировать необязательно apt-get install tcl # Скачать архив wget http://download.redis.io/redis-stable.tar.gz # Распаковать tar xzf redis-stable.tar.gz # Зайти в папку cd redis-stable # Собрать make && make install # Установить сервер utils/install_server.sh После вопросов, которые задаются после установки, и где я соглашался с ответами по умолчанию, конфиг выглядит так: Selected config: Port : 6379 Config file : /etc/redis/6379.conf Log file : /var/log/redis_6379.log Data dir : /var/lib/redis/6379 Executable : /usr/local/bin/redis-server Cli Executable : /usr/local/bin/redis-cli https://redis.io/download\\ http://easy-code.ru/lesson/install-and-use-redis === Установить плагин Redis для PHP === # Для сборки надо установить инструменты разработчика apt-get install php7.0-dev # Скачать wget https://github.com/phpredis/phpredis/archive/3.1.2.tar.gz # Распаковать tar xzf 3.1.2.tar.gz # Зайти в папку cd phpredis-3.1.2 # Сделать пакет прилагаемым скриптом .\mkdeb.sh # Установить make install Информация после установки: PHP : /usr/bin/php7.0 PHP_SAPI : cli PHP_VERSION : 7.0.18-0ubuntu0.16.04.1 ZEND_VERSION: 3.0.0 PHP_OS : Linux - Linux orangepipcplus 3.4.113-sun8i #10 SMP PREEMPT Thu Feb 23 19:55:00 CET 2017 armv7l INI actual : /root/redis-3.2.9/utils/phpredis-3.1.2/tmp-php.ini More .INIs : CWD : /root/redis-3.2.9/utils/phpredis-3.1.2 Extra dirs : VALGRIND : Not used Путь к плагину: Installing shared extensions: /usr/lib/php/20151012/ https://habrahabr.ru/post/134974/\\ https://habrahabr.ru/sandbox/60933/ ++++ ==== Настройка Nextcloud и разблокировка файлов ==== Конфиг Nextcloud в части кэширования нужно привести к следующему виду: 'memcache.local' => '\OC\Memcache\APCu', 'memcache.locking' => '\OC\Memcache\Redis', 'redis' => array( 'host' => 'localhost', 'port' => 6379, ), # Перевести Nextcloud в режим обслуживания: sudo -u www-data php /var/www/html/occ maintenance:mode --on # Зайти в базу "cloud" и очистить блокировки: mysql -u root -p cloud DELETE FROM oc_file_locks WHERE 1; quit # Вывести Nextcloud из режима обслуживания: sudo -u www-data php /var/www/html/occ maintenance:mode --off # Перезапустить Apache: systemctl restart apache2 ===== Дополнительные материалы ===== ==== Сертификаты ==== #Сделать папочку для сертификатов mkdir /etc/ssl/certs/nextcloud # самоподписанный сертификат на 10 лет без запроса пароля openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout /etc/ssl/certs/nextcloud/nextcloud.key -out /etc/ssl/certs/nextcloud/nextcloud.crt nano /etc/apache2/sites-available/default-ssl.conf SSLCertificateKeyFile /etc/ssl/certs/nextcloud/nextcloud.key SSLCertificateFile /etc/ssl/certs/nextcloud/nextcloud.crt #SSLCACertificateFile /etc/ssl/certs/nextcloud/nextcloud-int.crt FIXME sed -i ' /SSLCertificateKeyFile/c SSLCertificateKeyFile /etc/ssl/certs/nextcloud/nextcloud.key /SSLCertificateFile/c SSLCertificateFile /etc/ssl/certs/nextcloud/nextcloud.crt' /etc/apache2/sites-available/default-ssl.conf ==== Импорт контактов из файла vcf ==== Проблема: выгруженный файл vcf с мобильника на Android 4.4 не загружается в приложение "Контакты" в Nextcloud. Решение: - Открыть файл в программе [[http://alexboiko.narod.ru/prod.html|tcode]] (в Windows), чтобы строки с кодировкой Quoted Printable перекодировались в нормальный русский текст. Это можно сделать и из командной строки: tcode input.vcf /auto output.vcf - Убрать из всего файла строки **;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE** - Строки **VERSION:2.1** заменить на **VERSION:3.0** - Сохранить файл в кодировке UTF-8. ==== Ссылка на выгруженные контакты мобильным приложением ==== %%https://path-to-nextcloud-site.com/apps/files/?dir=/.Contacts-Backup%% ==== Полезные плагины ==== [[https://apps.nextcloud.com/apps/suspicious_login|Suspicious login detection]], [[https://apps.nextcloud.com/apps/audioplayer|Audio player]], [[https://apps.nextcloud.com/apps/onlyoffice|OnlyOffice]] === Плагин для Outlook === Версия 3: https://download.sendent.nl/addin/latest/Free/Free.zip ++++ Устаревший (версии 2) | https://download.nextcloud.com/outlook/ Ставить нужно плагин той же разрядности, что и у Офиса (не системы в целом). Cкачать свежую версию: # ((Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* | # ? {$_.Displayname -match 'Microsoft Office' -and $_.InstallLocation -match "\w"} | # select -expand installlocation -First 1) -split '\\')[1] -match 'x86' $offx64 = gci "$env:ProgramFiles\Microsoft Office\outlook.exe" -Recurse $offx86 = gci "${env:ProgramFiles(x86)}\Microsoft Office\outlook.exe" -Recurse $u = "https://download.nextcloud.com/outlook/" $f = (curl $u).links |? href -like "20*" | select -Last 1 -expand href $uf = $u + $f if ($offx64) { $plugx64 = (curl $uf).links |? href -like "*64*.msi" | select -expand href $url64 = $uf + $plugx64 curl $url64 -OutFile "$env:userprofile\Downloads\$plugx64" } if ($offx86) { $plugx86 = (curl $uf).links |? href -like "*86*.msi" | select -expand href $url86 = $uf + $plugx86 curl $url86 -OutFile "$env:userprofile\Downloads\$plugx86" } # Путь к файлам перевода: ${env:ProgramFiles(x86)}\Nextcloud Outlook\Resources\Translations Перевод на русский: { "Code":"ru-RU", "Description":"Russian", "Translations": { "btApply": "Применить", "btDay": "1 день", "btMonth": "1 месяц", "btWeek": "1 неделя", "btDefault": "Стандартно", "lblExplExpDate": "Здесь можно установить дату истечения срока действия для общего ресурса.", "btPassword": "Задать пароль", "btExpire": "Срок действия", "btUploadFU": "Выгрузить файлы", "btFiles": "Выбрать файлы", "lblExplFU": "Здесь вы можете выгрузить файлы на сервер Nextcloud, которые слишком велики для почтовых вложений.", "lblExplPass": "Здесь вы можете задать пароль для общего ресурса. Стандартно пароль генерируется автоматически.", "btGenerate": "Генерировать", "btSetup": "Подключение", "btAdvanced": "Доп. настройки", "lblServerVal": "Подключено к", "lblServerInv": "Не подключено!", "btClose": "Закрыть", "lblUrl": "URL сервера Nextcloud", "lblUsername": "Логин", "lblPassword": "Пароль", "btConnect": "Подключиться", "btUploadSF": "Создать общий ресурс", "lblExplSF": "Здесь вы можете создать пространство на сервере Nextcloud для получения файлов от ваших адресатов, чтобы они могли выгружать файлы сразу на сервер без необходимости слать их по электронной почте.", "titleExpDate": "Срок действия", "titleFU": "Добавить файлы к письму", "titlePassword": "Задать пароль", "titleSettings": "Настройки", "titleAdvanced": "Дополнительно", "titleActivity": "Обзор действий", "titleAuthenticate": "Веб-вход", "titleSetShareName": "Задать имя общего ресурса", "titleSetup": "Подключение", "titleSF": "Создание общего ресурса", "btShareFiles": "Выгрузить файлы", "btSharePublicFolder": "Дать общий доступ к папке", "btActivity": "Обзор действий", "btSettings": "Настройки", "gpUpload": "Выгрузить", "gpSettings": "Настройки", "gpActivity": "Действия", "gpNextcloud": "Nextcloud", "expDatePast": "Дата истечения срока действия не может быть в прошлом.", "viewExtendPwPolTxt": "Включена защита паролем, сгенерировать его автоматически?", "viewExtendPwPolTit": "Пароль не задан!", "passwordReq": "Заданный пароль не отвечает требованиям безопасности. Отсутствуют: ", "setupIncorrect": "Настройки заданы неверно. Проверьте URL сервера, имя пользователя и пароль.", "mainFileUploadCancelTxt": "Вы уверены, что хотите остановить выгрузку файлов?", "mainFileUploadCancelTit": "Внимание!", "noPassword": "Без пароля", "noExpDate": "Без срока действия", "settingsAdvancedFU": "HTML для выгрузки файлов", "settingsAdvancedSF": "HTML для общего доступа к папке", "btFilesClear": "Пусто", "lblLanguage": "Язык:", "enabled": "Включено", "disabled": "Отключено", "lblOverridePP": "Включить защиту паролем:", "UploadingFiles": "Выгрузка файлов", "UploadingFilesCancel": "Отмена выгрузки, подождите...", "OutlookAttachmentMode": "Режим вложения Outlook:", "btCancel": "Отмена", "btShareName": "Задать имя общего ресурса", "lblShareName": "Здесь вы можете задать произвольное имя для общего ресурса. Стандартно имя создаётся автоматически.", "titleShareName": "Имя общего ресурса", "dialogShareNameTextInUse": "Указанное имя общего ресурса '{0}' уже используется. Создать имя автоматически?", "dialogShareNameTitle": "Имя общего ресурса", "dialogShareNameNoName": "Имя общего ресурса не задано. Хотите использовать автоматически созданное?", "passwordNeeds": "Требования", "passwordCharacters": "символов как минимум", "passwordNumbers": "цифр", "passwordSpecials": "спецсимволов", "passwordLetters": "букв" }} ++++ ==== Автоудаление файлов ==== - Install [[https://apps.nextcloud.com/apps/files_automatedtagging|Automated Tagging]] and [[https://apps.nextcloud.com/apps/files_retention|Retention]] app. - Create a retention-parent tag and tag the /tmp directory with it. - Create tags like auto-delete-two-weeks and use those for the retention settings (Admin>Workflow>File retention) - Create an automation tagging rule which tags files with eg. auto-delete-two-weeks. As a condition choose that they must be tagged with retention-parent (files created inside the /tmp directory will have this retention-parent tag). - Test it by uploading a file to /tmp and check whether auto-delete-two-weeks has been attached to it. https://www.maxi-muth.de/3236/allgemeines/auto-delete-files-in-a-directory-after-a-certain-time-in-nextcloud/ В автотэге не работает выбор плагина Outlook - метки не назначаются. Если сделать по старинке через regex, то всё нормально (для старой версии плагина Outlook, для новой работает). Request user agent - matches - ((Mozilla\/).*( \().*(\))( Nextcloud-Outlook v).*) https://nextcloud.com/blog/controlling-file-retention-on-files-uploaded-with-the-outlook-add-in/ ==== Снежок ==== https://nextcloud.com/blog/holiday-fun-with-jsloader/ Установить плагин JSLoader, загрузить туда следующий код: ++++ snow.js | /** @license * DHTML Snowstorm! JavaScript-based snow for web pages * Making it snow on the internets since 2003. You're welcome. * ----------------------------------------------------------- * Version 1.44.20131208 (Previous rev: 1.44.20131125) * Copyright (c) 2007, Scott Schiller. All rights reserved. * Code provided under the BSD License * http://schillmania.com/projects/snowstorm/license.txt */ /*jslint nomen: true, plusplus: true, sloppy: true, vars: true, white: true */ /*global window, document, navigator, clearInterval, setInterval */ var snowStorm = (function(window, document) { // --- common properties --- this.autoStart = true; // Whether the snow should start automatically or not. this.excludeMobile = true; // Snow is likely to be bad news for mobile phones' CPUs (and batteries.) Enable at your own risk. this.flakesMax = 96; // Limit total amount of snow made (falling + sticking) this.flakesMaxActive = 48; // Limit amount of snow falling at once (less = lower CPU use) this.animationInterval = 33; // Theoretical "miliseconds per frame" measurement. 20 = fast + smooth, but high CPU use. 50 = more conservative, but slower this.useGPU = true; // Enable transform-based hardware acceleration, reduce CPU load. this.className = null; // CSS class name for further customization on snow elements this.excludeMobile = true; // Snow is likely to be bad news for mobile phones' CPUs (and batteries.) By default, be nice. this.flakeBottom = null; // Integer for Y axis snow limit, 0 or null for "full-screen" snow effect this.followMouse = true; // Snow movement can respond to the user's mouse this.snowColor = '#B2B5C6'; // Don't eat (or use?) yellow snow. this.snowCharacter = '❄'; // • = bullet, · is square on some systems etc. this.snowStick = true; // Whether or not snow should "stick" at the bottom. When off, will never collect. this.targetElement = null; // element which snow will be appended to (null = document.body) - can be an element ID eg. 'myDiv', or a DOM node reference this.useMeltEffect = true; // When recycling fallen snow (or rarely, when falling), have it "melt" and fade out if browser supports it this.useTwinkleEffect = true; // Allow snow to randomly "flicker" in and out of view while falling this.usePositionFixed = false; // true = snow does not shift vertically when scrolling. May increase CPU load, disabled by default - if enabled, used only where supported this.usePixelPosition = false; // Whether to use pixel values for snow top/left vs. percentages. Auto-enabled if body is position:relative or targetElement is specified. // --- less-used bits --- this.freezeOnBlur = true; // Only snow when the window is in focus (foreground.) Saves CPU. this.flakeLeftOffset = 0; // Left margin/gutter space on edge of container (eg. browser window.) Bump up these values if seeing horizontal scrollbars. this.flakeRightOffset = 0; // Right margin/gutter space on edge of container this.flakeWidth = 32; // Max pixel width reserved for snow element this.flakeHeight = 32; // Max pixel height reserved for snow element this.vMaxX = 5; // Maximum X velocity range for snow this.vMaxY = 4; // Maximum Y velocity range for snow this.zIndex = 5000; // CSS stacking order applied to each snowflake // --- "No user-serviceable parts inside" past this point, yadda yadda --- var storm = this, features, // UA sniffing and backCompat rendering mode checks for fixed position, etc. isIE = navigator.userAgent.match(/msie/i), isIE6 = navigator.userAgent.match(/msie 6/i), isMobile = navigator.userAgent.match(/mobile|opera m(ob|in)/i), isBackCompatIE = (isIE && document.compatMode === 'BackCompat'), noFixed = (isBackCompatIE || isIE6), screenX = null, screenX2 = null, screenY = null, scrollY = null, docHeight = null, vRndX = null, vRndY = null, windOffset = 1, windMultiplier = 2, flakeTypes = 6, fixedForEverything = false, targetElementIsRelative = false, opacitySupported = (function(){ try { document.createElement('div').style.opacity = '0.5'; } catch(e) { return false; } return true; }()), didInit = false, docFrag = document.createDocumentFragment(); features = (function() { var getAnimationFrame; /** * hat tip: paul irish * http://paulirish.com/2011/requestanimationframe-for-smart-animating/ * https://gist.github.com/838785 */ function timeoutShim(callback) { window.setTimeout(callback, 1000/(storm.animationInterval || 20)); } var _animationFrame = (window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || timeoutShim); // apply to window, avoid "illegal invocation" errors in Chrome getAnimationFrame = _animationFrame ? function() { return _animationFrame.apply(window, arguments); } : null; var testDiv; testDiv = document.createElement('div'); function has(prop) { // test for feature support var result = testDiv.style[prop]; return (result !== undefined ? prop : null); } // note local scope. var localFeatures = { transform: { ie: has('-ms-transform'), moz: has('MozTransform'), opera: has('OTransform'), webkit: has('webkitTransform'), w3: has('transform'), prop: null // the normalized property value }, getAnimationFrame: getAnimationFrame }; localFeatures.transform.prop = ( localFeatures.transform.w3 || localFeatures.transform.moz || localFeatures.transform.webkit || localFeatures.transform.ie || localFeatures.transform.opera ); testDiv = null; return localFeatures; }()); this.timer = null; this.flakes = []; this.disabled = false; this.active = false; this.meltFrameCount = 20; this.meltFrames = []; this.setXY = function(o, x, y) { if (!o) { return false; } if (storm.usePixelPosition || targetElementIsRelative) { o.style.left = (x - storm.flakeWidth) + 'px'; o.style.top = (y - storm.flakeHeight) + 'px'; } else if (noFixed) { o.style.right = (100-(x/screenX*100)) + '%'; // avoid creating vertical scrollbars o.style.top = (Math.min(y, docHeight-storm.flakeHeight)) + 'px'; } else { if (!storm.flakeBottom) { // if not using a fixed bottom coordinate... o.style.right = (100-(x/screenX*100)) + '%'; o.style.bottom = (100-(y/screenY*100)) + '%'; } else { // absolute top. o.style.right = (100-(x/screenX*100)) + '%'; o.style.top = (Math.min(y, docHeight-storm.flakeHeight)) + 'px'; } } }; this.events = (function() { var old = (!window.addEventListener && window.attachEvent), slice = Array.prototype.slice, evt = { add: (old?'attachEvent':'addEventListener'), remove: (old?'detachEvent':'removeEventListener') }; function getArgs(oArgs) { var args = slice.call(oArgs), len = args.length; if (old) { args[1] = 'on' + args[1]; // prefix if (len > 3) { args.pop(); // no capture } } else if (len === 3) { args.push(false); } return args; } function apply(args, sType) { var element = args.shift(), method = [evt[sType]]; if (old) { element[method](args[0], args[1]); } else { element[method].apply(element, args); } } function addEvent() { apply(getArgs(arguments), 'add'); } function removeEvent() { apply(getArgs(arguments), 'remove'); } return { add: addEvent, remove: removeEvent }; }()); function rnd(n,min) { if (isNaN(min)) { min = 0; } return (Math.random()*n)+min; } function plusMinus(n) { return (parseInt(rnd(2),10)===1?n*-1:n); } this.randomizeWind = function() { var i; vRndX = plusMinus(rnd(storm.vMaxX,0.2)); vRndY = rnd(storm.vMaxY,0.2); if (this.flakes) { for (i=0; i=0 && s.vX<0.2) { s.vX = 0.2; } else if (s.vX<0 && s.vX>-0.2) { s.vX = -0.2; } if (s.vY>=0 && s.vY<0.2) { s.vY = 0.2; } }; this.move = function() { var vX = s.vX*windOffset, yDiff; s.x += vX; s.y += (s.vY*s.vAmp); if (s.x >= screenX || screenX-s.x < storm.flakeWidth) { // X-axis scroll check s.x = 0; } else if (vX < 0 && s.x-storm.flakeLeftOffset < -storm.flakeWidth) { s.x = screenX-storm.flakeWidth-1; // flakeWidth; } s.refresh(); yDiff = screenY+scrollY-s.y+storm.flakeHeight; if (yDiff0.998) { // ~1/1000 chance of melting mid-air, with each frame s.melting = true; s.melt(); // only incrementally melt one frame // s.melting = false; } if (storm.useTwinkleEffect) { if (s.twinkleFrame < 0) { if (Math.random() > 0.97) { s.twinkleFrame = parseInt(Math.random() * 8, 10); } } else { s.twinkleFrame--; if (!opacitySupported) { s.o.style.visibility = (s.twinkleFrame && s.twinkleFrame % 2 === 0 ? 'hidden' : 'visible'); } else { s.o.style.opacity = (s.twinkleFrame && s.twinkleFrame % 2 === 0 ? 0 : 1); } } } } }; this.animate = function() { // main animation loop // move, check status, die etc. s.move(); }; this.setVelocities = function() { s.vX = vRndX+rnd(storm.vMaxX*0.12,0.1); s.vY = vRndY+rnd(storm.vMaxY*0.12,0.1); }; this.setOpacity = function(o,opacity) { if (!opacitySupported) { return false; } o.style.opacity = opacity; }; this.melt = function() { if (!storm.useMeltEffect || !s.melting) { s.recycle(); } else { if (s.meltFrame < s.meltFrameCount) { s.setOpacity(s.o,s.meltFrames[s.meltFrame]); s.o.style.fontSize = s.fontSize-(s.fontSize*(s.meltFrame/s.meltFrameCount))+'px'; s.o.style.lineHeight = storm.flakeHeight+2+(storm.flakeHeight*0.75*(s.meltFrame/s.meltFrameCount))+'px'; s.meltFrame++; } else { s.recycle(); } } }; this.recycle = function() { s.o.style.display = 'none'; s.o.style.position = (fixedForEverything?'fixed':'absolute'); s.o.style.bottom = 'auto'; s.setVelocities(); s.vCheck(); s.meltFrame = 0; s.melting = false; s.setOpacity(s.o,1); s.o.style.padding = '0px'; s.o.style.margin = '0px'; s.o.style.fontSize = s.fontSize+'px'; s.o.style.lineHeight = (storm.flakeHeight+2)+'px'; s.o.style.textAlign = 'center'; s.o.style.verticalAlign = 'baseline'; s.x = parseInt(rnd(screenX-storm.flakeWidth-20),10); s.y = parseInt(rnd(screenY)*-1,10)-storm.flakeHeight; s.refresh(); s.o.style.display = 'block'; s.active = 1; }; this.recycle(); // set up x/y coords etc. this.refresh(); }; this.snow = function() { var active = 0, flake = null, i, j; for (i=0, j=storm.flakes.length; istorm.flakesMaxActive) { storm.flakes[storm.flakes.length-1].active = -1; } } storm.targetElement.appendChild(docFrag); }; this.timerInit = function() { storm.timer = true; storm.snow(); }; this.init = function() { var i; for (i=0; i ++++ ===== Полезные команды ===== Включить превью офисных форматов: nano /var/www/html/config/config.php 'preview_libreoffice_path' => '/usr/bin/libreoffice', Перемещение файлов от одного пользователя к другому sudo -u www-data php /var/www/html/occ files:transfer-ownership --move user-from user-to https://docs.nextcloud.com/server/latest/admin_manual/configuration_server/occ_command.html#transfer Удалить пользователя username: sudo -u www-data php /var/www/html/occ user:delete username Почистить корзину у всех пользователей sudo -u www-data php /var/www/html/cloud/occ trashbin:cleanup --all-users ===== Решение проблем ===== ==== Failed to connect to www.nextcloud.com ==== В логах куча сообщений:\\ //GuzzleHttp\Exception\ConnectException: cURL error 7: Failed to connect to www.nextcloud.com port 80: Connection timed out// Сайт nexcloud.com реально бывает недоступен. Workaround - отключить проверку на наличие интернета: echo "'has_internet_connection' => false," >> /var/www/html/config/config.php Или не обращать внимания. ==== Some files have not passed the integrity check ==== После обновления - ошибка подписи файлов:\\ //Some files have not passed the integrity check. Further information on how to resolve this issue can be found in the documentation. (List of invalid files… / Rescan…)// Помимо выполнения [[https://docs.nextcloud.com/server/14/admin_manual/issues/code_signing.html#fixing-invalid-code-integrity-messages|рекомендаций]], убедиться, что core/signature.json актуальный. ==== Поломались "красивые" ссылки (без index.php) ==== Обновить файл .htaccess: sudo -u www-data php /var/www/html/occ maintenance:update:htaccess https://docs.nextcloud.com/server/14/admin_manual/installation/source_installation.html#pretty-urls ==== Specified key was too long; max key length is 767 bytes ==== При обновлении Nexcloud ошибка:\\ DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_bin ENGINE = InnoDB ROW_FORMAT = compressed': SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes Решение: mysql -u root -p cloud MariaDB [cloud]> set global innodb_large_prefix=on; MariaDB [cloud]> set global innodb_file_format=Barracuda; quit sudo -u www-data php /var/www/html/occ maintenance:repair sudo -u www-data php /var/www/html/occ upgrade ==== The database is missing some indexes ==== Проверка в админке пишет: The database is missing some indexes Решение: sudo -u www-data php /var/www/html/occ db:add-missing-indices # В докере: docker exec -u www-data nc php occ db:add-missing-indices ==== Обновление прошло неуспешно, PHP грузит систему на 100%, сайт в неотключаемом maintenance mode ==== Отключить регулярную задачу в crontab.\\ # Проверить, включен ли apc cli: php -i | grep apc.enable apc.enable_cli => Off => Off apc.enabled => On => On # Если нет, то включить echo "apc.enable_cli=1" >> /etc/php/7.4/cli/php.ini # Перейти в каталог NC (обязательно!) и запустить апгрейд заново cd /var/www/html/cloud sudo -u www-data php occ upgrade Включить регулярную задачу в crontab. https://help.nextcloud.com/t/nextcloud-21-update-needed/108714/25 ==== "Module php-imagick in this instance has no SVG support. For better compatibility it is recommended to install it ==== # Для Alpine. Для контейнера добавить этот пакет в докерфайл. apk add imagemagick-svg # Старое решение apt-get install libmagickcore-6.q16-6-extra https://www.reddit.com/r/NextCloud/comments/11fb4rs/module_phpimagick_in_this_instance_has_no_svg/\\ https://help.nextcloud.com/t/how-to-enable-svg-for-php-imagick/108646/4 ==== Your installation has no default phone region set ==== sudo -u www-data php /var/www/html/occ config:system:set default_phone_region --value="RU" # Докер docker exec -u www-data nc php occ config:system:set default_phone_region --value="RU" ==== Last background job execution ran 15 hours ago. Something seems wrong ==== Запустить принудительно sudo -u www-data php -f /var/www/html/cloud/cron.php ==== PHP Fatal error: Out of memory (allocated 3533701120) (tried to allocate 36864 bytes) in /var/www/html/lib/private/AppFramework/Utility/SimpleContainer.php on line 133 ==== При выполнении PHP cron. I had APCu activated in the nextcloud config.php. It seems I didn’t have ''apc.enable_cli=1'' in ''/etc/php/8.0/cli/conf.d/20-apcu.ini''. After I added that line to the file occ worked and there was no segmentation error anymore. https://help.nextcloud.com/t/solved-occ-command-php-fatal-error-allowed-memory-size-of-xxx-bytes-exhausted/108521/16 ==== Docker - The reverse proxy header configuration is incorrect ==== Warning: The reverse proxy header configuration is incorrect, or you are accessing Nextcloud from a trusted proxy. If not, this is a security issue and can allow an attacker to spoof their IP address as visible to the Nextcloud. Further information can be found in the documentation. docker exec -uwww-data nc-php php /var/www/html/cloud/occ config:system:set forwarded_for_headers 0 --value="X-Forwarded-For" # docker exec -uwww-data nc-php php /var/www/html/cloud/occ config:system:set forwarded_for_headers 1 --value="HTTP_X_FORWARDED_FOR" # Сейчас NC не ориентируется на DNS-имя прокси, ему подавай IP, иначе статус красный. # Решение - добавить подсеть, причём, единственным пунктом docker exec -uwww-data nc-php php /var/www/html/cloud/occ config:system:set trusted_proxies 0 --value="172.16.0.0/12" # docker exec -uwww-data nc-php php /var/www/html/cloud/occ config:system:set trusted_proxies 1 --value=reverse-proxy https://github.com/nextcloud/docker/issues/800\\ https://docs.nextcloud.com/server/latest/admin_manual/configuration_server/reverse_proxy_configuration.html ==== Docker - exec: "php": executable file not found in $PATH ==== После обновления контейнера PHP с версии 7.4 на 8.0 при попытке выполнить команду php occ внутри контейнера выдаётся ошибка:\\ OCI runtime exec failed: exec failed: unable to start container process: exec: "php": executable file not found in $PATH: unknown Проблема в том, что в дистрибутиве Alpine автоматически не создаётся символическая ссылка php8 -> php, т. к. для php8 не готовы все пакеты. Решение: добавить в Dockerfile ln -sf /usr/bin/php8 /usr/bin/php # -f - перезаписывать, если она уже есть (после предыдущего создания) ==== The __Host prefix mitigates cookie injection ==== https://scan.nextcloud.com: The __Host prefix mitigates cookie injection vulnerabilities within potential third-party software sharing the same second level domain. It is an additional hardening on top of 'normal' same-site cookies. Предположительное решение: https://github.com/DoTheEvo/selfhosted-apps-docker/issues/7 ==== Клиент виснет после начала синхронизации ==== Ситуация - виснет клиент практически сразу после запуска, нагружает процессор, настройки открыть невозможно, в логах ничего внятного, переустановка на разные версии, удаление служебных файлов в каталоге синхронизации ничего не даёт. Решение: # убить процесс Get-Process nextcloud |kill # запустить синхронизацию с помощью nextcloudcmd "$env:programfiles\Nextcloud\nextcloudcmd.exe" --silent ` "$env:userprofile\Nextcloud" https://bva.dyndns.info/cloud Затем запустить клиента, зайти в Настройки -> Сеть и убрать ограничения на скорость загрузки/передачи. https://docs.nextcloud.com/desktop/latest/advancedusage.html#nextcloud-command-line-client ==== Операция не разрешена модулем контроля доступа ==== Operation is blocked by access control Симптом - маленькие файлы грузятся, а больше примерно 10 МБ - нет. Решение - разрешить на реверс-прокси url c ''/.'' https://help.nextcloud.com/t/nextcloud-17-nginx-unable-to-upload-files-larger-than-unknown-size/67624/2 ==== X-Robots-Tag HTTP header is not set ==== The "X-Robots-Tag" HTTP header is not set to "noindex, nofollow". This is a potential security or privacy risk, as it is recommended to adjust this setting accordingly. Поменять опцию в ''nginx/conf.d/default.conf'' add_header X-Robots-Tag "none" always; # на add_header X-Robots-Tag "noindex, nofollow" always; Because “none” is indeed equivalent to “noindex, nofollow” for Google, but seems to be not supported by Bing and probably other search engines. (https://help.nextcloud.com/t/x-robots-tag-http-header-not-configured-with-noindex-nofollow-since-nc-26-0-0/158300) ==== OPcache interned strings buffer is nearly full ==== The OPcache interned strings buffer is nearly full. To assure that repeating strings can be effectively cached, it is recommended to apply opcache.interned_strings_buffer to your PHP configuration with a value higher than 8. sed -i '/opcache.interned_strings_buffer =/c opcache.interned_strings_buffer = 16/' /etc/php/8.2/fpm/php.ini systemctl restart php-fpm ==== OnlyOffice не работает после обновления Nextcloud на версию 28 ==== В логе Exception array_merge(): Argument #2 must be of type array, null given in file '[...]/lib/public/AppFramework/Http/Response.php' line 273 Временное решение: в файле ''lib/public/AppFramework/Http/Response.php'' в строке 273: return array_merge($mergeWith, $this->headers); # заменить на return array_merge($mergeWith, $this->headers?? []); sed -i '273s/headers.*/headers?? []);/' /var/www/html/lib/public/AppFramework/Http/Response.php ==== Could not check for JavaScript support ==== Could not check for JavaScript support. Please check manually if your webserver serves `.mjs` files using the JavaScript MIME type. https://docs.nextcloud.com/server/latest/admin_manual/installation/nginx.html ==== Server has no maintenance window start time configured ==== Server has no maintenance window start time configured. This means resource intensive daily background jobs will also be executed during your main usage time. We recommend to set it to a time of low usage, so users are less impacted by the load caused from these heavy tasks. A value of 1 e.g. will only run these background jobs between 01:00am UTC and 05:00am UTC. 'maintenance_window_start' => 1, https://docs.nextcloud.com/server/latest/admin_manual/configuration_server/config_sample_php_parameters.html#maintenance-window-start\\ https://docs.nextcloud.com/server/latest/admin_manual/configuration_server/background_jobs_configuration.html ==== Expected filesize of X bytes but read (from Nextcloud client) and wrote (to Nextcloud storage) Y bytes ==== Проблема закачки файлов в Nextcloud. [no app in context] Error: Expected filesize of 6609487 bytes but read (from Nextcloud client) and wrote (to Nextcloud storage) 4833280 bytes. Could either be a network problem on the sending side or a problem writing to the storage on the server side. Причина в реверс-прокси Traefik, у которого с какого-то момента изменилось умолчание readTimeout с 0 до 60 сек, и он рвёт соединение. Если поставить обратно 0, всё начинает нормально работать. --entryPoints.web.transport.respondingTimeouts.readTimeout=0s # Либо добавить переменную в Докере TRAEFIK_ENTRYPOINTS_WEB_TRANSPORT_RESPONDINGTIMEOUTS_READTIMEOUT: "0s" https://github.com/nextcloud/server/issues/37695#issuecomment-2259203772 ===== Ссылки ===== [[https://nextcloud.com/changelog/|Changelog на сайте производителя]]\\ [[https://download.nextcloud.com/server/releases/|Страница со списком релизов]]\\ [[https://scan.nextcloud.com/|Сканер безопасности]]\\ [[https://nextcloud.com/install/#install-clients|Скачать клиенты для компьютеров и мобильных устройств]] https://docs.nextcloud.com/server/latest/admin_manual/configuration_server/occ_command.html