service:nextcloud
Различия
Показаны различия между двумя версиями страницы.
Предыдущая версия справа и слеваПредыдущая версияСледующая версия | Предыдущая версия | ||
service:nextcloud [02.02.2024 05:51] – [Настройка] viacheslav | service:nextcloud [14.03.2025 10:21] (текущий) – [High-performance backend (HPB)] viacheslav | ||
---|---|---|---|
Строка 1: | Строка 1: | ||
+ | ====== Nextcloud ====== | ||
+ | По ходу инсталляции, | ||
+ | |||
+ | ===== Установка и настройка системы и необходимых компонентов ===== | ||
+ | Во время установки Ubuntu Server, отметить для установки SSH Server и LAMP. Выбрать автоустановку обновлений безопасности. | ||
+ | <code bash> | ||
+ | # Войти в режим рута | ||
+ | sudo -i | ||
+ | # Задать статический IP: | ||
+ | nano / | ||
+ | </ | ||
+ | < | ||
+ | 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 и обновить систему целиком: | ||
+ | <code bash> | ||
+ | sudo -i | ||
+ | apt-get update && apt-get upgrade -y && apt-get dist-upgrade -y && apt-get autoremove | ||
+ | </ | ||
+ | |||
+ | Установить все необходимые компоненты и, в данном случае, | ||
+ | <code bash> | ||
+ | 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: | ||
+ | <code bash> | ||
+ | apt-get install smbclient php-ldap mc -y | ||
+ | </ | ||
+ | |||
+ | ===== Клиент ===== | ||
+ | https:// | ||
+ | <code powershell> | ||
+ | # WebDAV | ||
+ | https:// | ||
+ | </ | ||
+ | ===== Установка Nextcloud ===== | ||
+ | <code bash> | ||
+ | # Скачать последнюю версию | ||
+ | wget https:// | ||
+ | # Распаковать архив в корневую папку веб-сервера | ||
+ | tar xjf latest.tar.bz2 --strip=1 -C / | ||
+ | # Удалить исходный архив (если нужно) | ||
+ | rm latest.tar.bz2 | ||
+ | # Создать папку для пользовательских данных | ||
+ | mkdir / | ||
+ | # Дать права владельца веб-серверу: | ||
+ | chown -R www-data: | ||
+ | # Перезапустить Apache: | ||
+ | systemctl restart apache2 | ||
+ | # Создать базу MySQL с именем " | ||
+ | mysql -u root -p -e " | ||
+ | </ | ||
+ | |||
+ | Открыть браузер, | ||
+ | FIXME - уточнить, | ||
+ | <code bash> | ||
+ | sudo -u www-data php / | ||
+ | </ | ||
+ | ===== Настройка ===== | ||
+ | <code bash> | ||
+ | # Убрать закрывающую строку из конфига и заменить строку overwrite.cli.url на нужную. | ||
+ | # В sed экранирование апострофа безумное - '"'"' | ||
+ | sed -i ' | ||
+ | /);/d | ||
+ | / | ||
+ | |||
+ | # Настроить конфиг - " | ||
+ | echo "' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ), | ||
+ | ' | ||
+ | ' | ||
+ | );" >> / | ||
+ | |||
+ | # Настроить максимальный размер файла на закачку в PHP и лимит памяти | ||
+ | # Проверить версию PHP и путь к используемым php.ini (php --ini), например, | ||
+ | # / | ||
+ | # / | ||
+ | sed -i ' | ||
+ | / | ||
+ | / | ||
+ | / | ||
+ | |||
+ | # Настроить параметры opcache | ||
+ | sed -i ' | ||
+ | / | ||
+ | / | ||
+ | / | ||
+ | / | ||
+ | / | ||
+ | / | ||
+ | / | ||
+ | / | ||
+ | ' / | ||
+ | </ | ||
+ | |||
+ | [[http:// | ||
+ | ==== SSL, mod_env и mod_rewrite для pretty URLs ==== | ||
+ | <code bash> | ||
+ | a2enmod ssl headers env rewrite && a2ensite default-ssl | ||
+ | </ | ||
+ | |||
+ | Включить Strict transport security, [[https:// | ||
+ | <code bash> | ||
+ | echo "< | ||
+ | | ||
+ | | ||
+ | </ | ||
+ | |||
+ | # Set Forward Secrecy | ||
+ | SSLProtocol all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1 | ||
+ | SSLHonorCipherOrder on | ||
+ | SSLCipherSuite HIGH: | ||
+ | " >> / | ||
+ | </ | ||
+ | |||
+ | ==== Перенаправить HTTP на HTTPS ==== | ||
+ | nano / | ||
+ | <code bash> | ||
+ | < | ||
+ | ServerName www.yourdomain.com | ||
+ | Redirect / https:// | ||
+ | </ | ||
+ | </ | ||
+ | <code bash> | ||
+ | systemctl restart apache2 | ||
+ | </ | ||
+ | |||
+ | ==== Настроить Pretty URLs ==== | ||
+ | <code bash> | ||
+ | nano / | ||
+ | |||
+ | # В разделе < | ||
+ | # Выйти из редактора. | ||
+ | |||
+ | # Обновить файл .htaccess: | ||
+ | sudo -u www-data php / | ||
+ | |||
+ | # Перезапустить Apache: | ||
+ | systemctl restart apache2 | ||
+ | </ | ||
+ | |||
+ | ==== Переключить фоновые задачи на выполнение кроном ==== | ||
+ | <code bash> | ||
+ | echo "# Nextcloud cron schedule" | ||
+ | echo " | ||
+ | |||
+ | sudo -u www-data php / | ||
+ | </ | ||
+ | https:// | ||
+ | |||
+ | ==== Выключить ненужные ссылки ==== | ||
+ | config/ | ||
+ | <code php> | ||
+ | # Выключить ссылку на сброс пароля | ||
+ | ' | ||
+ | # Remove link “Get your own free account” | ||
+ | ' | ||
+ | </ | ||
+ | |||
+ | ==== Настроить аутентификацию через LDAP ==== | ||
+ | |||
+ | Для работы этого типа аутентификации необходимо установить компонент php-ldap, если он не был установлен ранее: | ||
+ | <code bash> | ||
+ | apt-get install php-ldap -y | ||
+ | </ | ||
+ | |||
+ | ++++Далее настройка производится в веб-интерфейсе админа. | | ||
+ | |||
+ | Прописать адрес контроллера домена, | ||
+ | {{: | ||
+ | |||
+ | Выборку критериев отбора объектов лучше всего прописывать вручную - в этом случае отключенные в AD пользователи исчезнут и из пользователей Nextcloud. Вот эта строка: | ||
+ | < | ||
+ | (& | ||
+ | </ | ||
+ | {{: | ||
+ | |||
+ | Вкладка Advanced - Connection settings: прописать запасной контроллер домена.\\ | ||
+ | {{: | ||
+ | |||
+ | Вкладка Advanced - Directory settings: указать, | ||
+ | {{: | ||
+ | |||
+ | Вкладка Advanced - Special attributes: задаём, | ||
+ | {{: | ||
+ | |||
+ | Вкладка Expert: задать внутреннее имя пользователя как логин в AD вместо неудобоваримого UUID.\\ | ||
+ | {{: | ||
+ | |||
+ | ==== Онлайн-офис ==== | ||
+ | <code powershell> | ||
+ | # Collabora (довольно тормозной вариант) | ||
+ | sudo -u www-data php / | ||
+ | |||
+ | # OnlyOffice (ограничение в 20 соединений в бесплатной версии) | ||
+ | sudo -u www-data php / | ||
+ | </ | ||
+ | |||
+ | Для OnlyOffice, добавить в ''/ | ||
+ | <code php> | ||
+ | ' | ||
+ | array ( | ||
+ | ' | ||
+ | ), | ||
+ | ' | ||
+ | </ | ||
+ | |||
+ | OnlyOffice - работа через прокси: | ||
+ | |||
+ | " | ||
+ | <code php> | ||
+ | ' | ||
+ | ' | ||
+ | </ | ||
+ | https:// | ||
+ | |||
+ | ==== Внешние хранилища ==== | ||
+ | === S3 === | ||
+ | Способ доступа - Access key\\ | ||
+ | Bucket - каталог в облаке, | ||
+ | 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 | ||
+ | |||
+ | ===== Обновление ===== | ||
+ | <code bash> | ||
+ | # Автоматически: | ||
+ | sudo -u www-data php / | ||
+ | |||
+ | # Вручную: | ||
+ | # Скачать последний релиз | ||
+ | wget https:// | ||
+ | # Распаковать скачанный архив в папку установки | ||
+ | tar xjf latest.tar.bz2 --strip=1 -C / | ||
+ | # Дать права владельца веб-серверу: | ||
+ | chown -R www-data: | ||
+ | # Включить режим обслуживания | ||
+ | sudo -u www-data php / | ||
+ | # Запустить процесс обновления | ||
+ | sudo -u www-data php / | ||
+ | # Выключить режим обслуживания | ||
+ | sudo -u www-data php / | ||
+ | </ | ||
+ | https:// | ||
+ | |||
+ | Экспресс-обновление со сменой шлюза | ||
+ | <code bash> | ||
+ | ip route change default via 192.168.1.254 dev eth0 | ||
+ | apt update && apt upgrade -y && apt autoremove -y | ||
+ | sudo -u www-data php / | ||
+ | ip route change default via 192.168.1.1 dev eth0 | ||
+ | </ | ||
+ | |||
+ | Обновление на след. мажорный релиз | ||
+ | <code bash> | ||
+ | # Нужно переключиться на бета-канал обновлений, | ||
+ | sudo -u www-data php / | ||
+ | sudo -u www-data php / | ||
+ | sudo -u www-data php / | ||
+ | </ | ||
+ | |||
+ | В Докере | ||
+ | <code bash> | ||
+ | docker exec nc-php sudo -u www-data php / | ||
+ | docker exec nc-php sudo -u www-data php / | ||
+ | docker exec nc-php sudo -u www-data php / | ||
+ | </ | ||
+ | |||
+ | ==== Обновление всех приложений ==== | ||
+ | <code bash> | ||
+ | sudo -u www-data php / | ||
+ | # docker | ||
+ | docker exec -uwww-data nc-php php / | ||
+ | </ | ||
+ | |||
+ | ===== Настройка кэширования через сервер Redis ===== | ||
+ | Как-то раз произошла ситуация - невозможно было стереть файл с сервера или обновить его, файл был заблокирован: | ||
+ | <WRAP round alert 60%> | ||
+ | file is locked\\ | ||
+ | Error transferring bva.dyndns.info/ | ||
+ | </ | ||
+ | |||
+ | [[https:// | ||
+ | |||
+ | В Ubuntu это ставится просто, | ||
+ | |||
+ | ==== Установить Redis ==== | ||
+ | <WRAP round important 60%> | ||
+ | Информация устарела, | ||
+ | Теперь достаточно выполнить команду\\ | ||
+ | apt-get install redis-server php-redis | ||
+ | </ | ||
+ | |||
+ | ++++ Сборка из исходников | | ||
+ | <code bash> | ||
+ | # Установить пакет tcl для возможности протестировать инсталлятор после сборки, | ||
+ | apt-get install tcl | ||
+ | # Скачать архив | ||
+ | wget http:// | ||
+ | # Распаковать | ||
+ | tar xzf redis-stable.tar.gz | ||
+ | # Зайти в папку | ||
+ | cd redis-stable | ||
+ | # Собрать | ||
+ | make && make install | ||
+ | # Установить сервер | ||
+ | utils/ | ||
+ | </ | ||
+ | |||
+ | После вопросов, | ||
+ | < | ||
+ | Selected config: | ||
+ | Port : 6379 | ||
+ | Config file : / | ||
+ | Log file : / | ||
+ | Data dir : / | ||
+ | Executable | ||
+ | Cli Executable : / | ||
+ | </ | ||
+ | |||
+ | https:// | ||
+ | http:// | ||
+ | |||
+ | === Установить плагин Redis для PHP === | ||
+ | <code bash> | ||
+ | # Для сборки надо установить инструменты разработчика | ||
+ | apt-get install php7.0-dev | ||
+ | # Скачать | ||
+ | wget https:// | ||
+ | # Распаковать | ||
+ | tar xzf 3.1.2.tar.gz | ||
+ | # Зайти в папку | ||
+ | cd phpredis-3.1.2 | ||
+ | # Сделать пакет прилагаемым скриптом | ||
+ | .\mkdeb.sh | ||
+ | # Установить | ||
+ | make install | ||
+ | </ | ||
+ | |||
+ | Информация после установки: | ||
+ | < | ||
+ | PHP : / | ||
+ | PHP_SAPI | ||
+ | PHP_VERSION : 7.0.18-0ubuntu0.16.04.1 | ||
+ | ZEND_VERSION: | ||
+ | PHP_OS | ||
+ | INI actual | ||
+ | More .INIs : | ||
+ | CWD : / | ||
+ | Extra dirs : | ||
+ | VALGRIND | ||
+ | </ | ||
+ | |||
+ | Путь к плагину: | ||
+ | < | ||
+ | Installing shared extensions: | ||
+ | </ | ||
+ | |||
+ | https:// | ||
+ | https:// | ||
+ | ++++ | ||
+ | ==== Настройка Nextcloud и разблокировка файлов ==== | ||
+ | Конфиг Nextcloud в части кэширования нужно привести к следующему виду: | ||
+ | <code php> | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ), | ||
+ | </ | ||
+ | |||
+ | <code bash> | ||
+ | # Перевести Nextcloud в режим обслуживания: | ||
+ | sudo -u www-data php / | ||
+ | # Зайти в базу " | ||
+ | mysql -u root -p cloud | ||
+ | </ | ||
+ | <code mysql> | ||
+ | DELETE FROM oc_file_locks WHERE 1; | ||
+ | quit | ||
+ | </ | ||
+ | |||
+ | <code bash> | ||
+ | # Вывести Nextcloud из режима обслуживания: | ||
+ | sudo -u www-data php / | ||
+ | # Перезапустить Apache: | ||
+ | systemctl restart apache2 | ||
+ | </ | ||
+ | |||
+ | |||
+ | ===== Дополнительные материалы ===== | ||
+ | ==== Сертификаты ==== | ||
+ | <code bash> | ||
+ | # | ||
+ | mkdir / | ||
+ | # самоподписанный сертификат на 10 лет без запроса пароля | ||
+ | openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout / | ||
+ | </ | ||
+ | |||
+ | <code bash> | ||
+ | nano / | ||
+ | </ | ||
+ | < | ||
+ | SSLCertificateKeyFile / | ||
+ | SSLCertificateFile / | ||
+ | # | ||
+ | </ | ||
+ | |||
+ | FIXME | ||
+ | <code bash> | ||
+ | sed -i ' | ||
+ | / | ||
+ | / | ||
+ | </ | ||
+ | |||
+ | ==== Импорт контактов из файла vcf ==== | ||
+ | Проблема: | ||
+ | |||
+ | Решение: | ||
+ | - Открыть файл в программе [[http:// | ||
+ | - Убрать из всего файла строки **; | ||
+ | - Строки **VERSION: | ||
+ | - Сохранить файл в кодировке UTF-8. | ||
+ | ==== Ссылка на выгруженные контакты мобильным приложением ==== | ||
+ | %%https:// | ||
+ | |||
+ | ==== Полезные плагины ==== | ||
+ | [[https:// | ||
+ | === Плагин для Outlook === | ||
+ | Версия 3: https:// | ||
+ | |||
+ | ++++ Устаревший (версии 2) | | ||
+ | https:// | ||
+ | Ставить нужно плагин той же разрядности, | ||
+ | |||
+ | Cкачать свежую версию: | ||
+ | <code powershell> | ||
+ | # ((Get-ItemProperty HKLM: | ||
+ | # ? {$_.Displayname -match ' | ||
+ | # select -expand installlocation -First 1) -split ' | ||
+ | |||
+ | $offx64 = gci " | ||
+ | $offx86 = gci " | ||
+ | $u = " | ||
+ | $f = (curl $u).links |? href -like " | ||
+ | $uf = $u + $f | ||
+ | if ($offx64) { | ||
+ | $plugx64 = (curl $uf).links |? href -like " | ||
+ | $url64 = $uf + $plugx64 | ||
+ | curl $url64 -OutFile " | ||
+ | } | ||
+ | if ($offx86) { | ||
+ | $plugx86 = (curl $uf).links |? href -like " | ||
+ | $url86 = $uf + $plugx86 | ||
+ | curl $url86 -OutFile " | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | <code powershell> | ||
+ | # Путь к файлам перевода: | ||
+ | ${env: | ||
+ | </ | ||
+ | |||
+ | Перевод на русский: | ||
+ | <code json> | ||
+ | { | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | }} | ||
+ | </ | ||
+ | |||
+ | ++++ | ||
+ | ==== Автоудаление файлов ==== | ||
+ | - Install [[https:// | ||
+ | - 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> | ||
+ | - 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:// | ||
+ | |||
+ | В автотэге не работает выбор плагина Outlook - метки не назначаются. Если сделать по старинке через regex, то всё нормально (для старой версии плагина Outlook, для новой работает). | ||
+ | < | ||
+ | Request user agent - matches - ((Mozilla\/ | ||
+ | </ | ||
+ | https:// | ||
+ | ==== Снежок ==== | ||
+ | https:// | ||
+ | |||
+ | Установить плагин JSLoader, загрузить туда следующий код: | ||
+ | |||
+ | ++++ snow.js | | ||
+ | <file javascript 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:// | ||
+ | */ | ||
+ | /*jslint nomen: true, plusplus: true, sloppy: true, vars: true, white: true */ | ||
+ | /*global window, document, navigator, clearInterval, | ||
+ | |||
+ | var snowStorm = (function(window, | ||
+ | |||
+ | // --- 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' | ||
+ | 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 " | ||
+ | this.useGPU = true; // Enable transform-based hardware acceleration, | ||
+ | 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' | ||
+ | this.flakeBottom = null; // Integer for Y axis snow limit, 0 or null for " | ||
+ | this.followMouse = true; // Snow movement can respond to the user's mouse | ||
+ | this.snowColor = '# | ||
+ | this.snowCharacter = ' | ||
+ | this.snowStick = true; // Whether or not snow should " | ||
+ | this.targetElement = null; // element which snow will be appended to (null = document.body) - can be an element ID eg. ' | ||
+ | this.useMeltEffect = true; // When recycling fallen snow (or rarely, when falling), have it " | ||
+ | this.useTwinkleEffect = true; // Allow snow to randomly " | ||
+ | this.usePositionFixed = false; | ||
+ | this.usePixelPosition = false; | ||
+ | |||
+ | // --- less-used bits --- | ||
+ | |||
+ | this.freezeOnBlur = true; // Only snow when the window is in focus (foreground.) Saves CPU. | ||
+ | this.flakeLeftOffset = 0; // Left margin/ | ||
+ | this.flakeRightOffset = 0; // Right margin/ | ||
+ | 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" | ||
+ | |||
+ | var storm = this, | ||
+ | features, | ||
+ | // UA sniffing and backCompat rendering mode checks for fixed position, etc. | ||
+ | isIE = navigator.userAgent.match(/ | ||
+ | isIE6 = navigator.userAgent.match(/ | ||
+ | isMobile = navigator.userAgent.match(/ | ||
+ | isBackCompatIE = (isIE && document.compatMode === ' | ||
+ | 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(' | ||
+ | } catch(e) { | ||
+ | return false; | ||
+ | } | ||
+ | return true; | ||
+ | }()), | ||
+ | didInit = false, | ||
+ | docFrag = document.createDocumentFragment(); | ||
+ | |||
+ | features = (function() { | ||
+ | |||
+ | var getAnimationFrame; | ||
+ | |||
+ | /** | ||
+ | * hat tip: paul irish | ||
+ | * http:// | ||
+ | * https:// | ||
+ | */ | ||
+ | |||
+ | function timeoutShim(callback) { | ||
+ | window.setTimeout(callback, | ||
+ | } | ||
+ | |||
+ | var _animationFrame = (window.requestAnimationFrame || | ||
+ | window.webkitRequestAnimationFrame || | ||
+ | window.mozRequestAnimationFrame || | ||
+ | window.oRequestAnimationFrame || | ||
+ | window.msRequestAnimationFrame || | ||
+ | timeoutShim); | ||
+ | |||
+ | // apply to window, avoid " | ||
+ | getAnimationFrame = _animationFrame ? function() { | ||
+ | return _animationFrame.apply(window, | ||
+ | } : null; | ||
+ | |||
+ | var testDiv; | ||
+ | |||
+ | testDiv = document.createElement(' | ||
+ | |||
+ | 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(' | ||
+ | moz: has(' | ||
+ | opera: has(' | ||
+ | webkit: has(' | ||
+ | w3: has(' | ||
+ | prop: null // the normalized property value | ||
+ | }, | ||
+ | |||
+ | 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) + ' | ||
+ | o.style.top = (y - storm.flakeHeight) + ' | ||
+ | |||
+ | } else if (noFixed) { | ||
+ | |||
+ | o.style.right = (100-(x/ | ||
+ | // avoid creating vertical scrollbars | ||
+ | o.style.top = (Math.min(y, | ||
+ | |||
+ | } else { | ||
+ | |||
+ | if (!storm.flakeBottom) { | ||
+ | |||
+ | // if not using a fixed bottom coordinate... | ||
+ | o.style.right = (100-(x/ | ||
+ | o.style.bottom = (100-(y/ | ||
+ | |||
+ | } else { | ||
+ | |||
+ | // absolute top. | ||
+ | o.style.right = (100-(x/ | ||
+ | o.style.top = (Math.min(y, | ||
+ | |||
+ | } | ||
+ | |||
+ | } | ||
+ | |||
+ | }; | ||
+ | |||
+ | this.events = (function() { | ||
+ | |||
+ | var old = (!window.addEventListener && window.attachEvent), | ||
+ | evt = { | ||
+ | add: (old?' | ||
+ | remove: (old?' | ||
+ | }; | ||
+ | |||
+ | function getArgs(oArgs) { | ||
+ | var args = slice.call(oArgs), | ||
+ | if (old) { | ||
+ | args[1] = ' | ||
+ | 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], | ||
+ | } else { | ||
+ | element[method].apply(element, | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function addEvent() { | ||
+ | apply(getArgs(arguments), | ||
+ | } | ||
+ | |||
+ | function removeEvent() { | ||
+ | apply(getArgs(arguments), | ||
+ | } | ||
+ | |||
+ | 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), | ||
+ | } | ||
+ | |||
+ | this.randomizeWind = function() { | ||
+ | var i; | ||
+ | vRndX = plusMinus(rnd(storm.vMaxX, | ||
+ | vRndY = rnd(storm.vMaxY, | ||
+ | if (this.flakes) { | ||
+ | for (i=0; i< | ||
+ | if (this.flakes[i].active) { | ||
+ | this.flakes[i].setVelocities(); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | }; | ||
+ | |||
+ | this.scrollHandler = function() { | ||
+ | var i; | ||
+ | // " | ||
+ | scrollY = (storm.flakeBottom ? 0 : parseInt(window.scrollY || document.documentElement.scrollTop || (noFixed ? document.body.scrollTop : 0), 10)); | ||
+ | if (isNaN(scrollY)) { | ||
+ | scrollY = 0; // Netscape 6 scroll fix | ||
+ | } | ||
+ | if (!fixedForEverything && !storm.flakeBottom && storm.flakes) { | ||
+ | for (i=0; i< | ||
+ | if (storm.flakes[i].active === 0) { | ||
+ | storm.flakes[i].stick(); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | }; | ||
+ | |||
+ | this.resizeHandler = function() { | ||
+ | if (window.innerWidth || window.innerHeight) { | ||
+ | screenX = window.innerWidth - 16 - storm.flakeRightOffset; | ||
+ | screenY = (storm.flakeBottom || window.innerHeight); | ||
+ | } else { | ||
+ | screenX = (document.documentElement.clientWidth || document.body.clientWidth || document.body.scrollWidth) - (!isIE ? 8 : 0) - storm.flakeRightOffset; | ||
+ | screenY = storm.flakeBottom || document.documentElement.clientHeight || document.body.clientHeight || document.body.scrollHeight; | ||
+ | } | ||
+ | docHeight = document.body.offsetHeight; | ||
+ | screenX2 = parseInt(screenX/ | ||
+ | }; | ||
+ | |||
+ | this.resizeHandlerAlt = function() { | ||
+ | screenX = storm.targetElement.offsetWidth - storm.flakeRightOffset; | ||
+ | screenY = storm.flakeBottom || storm.targetElement.offsetHeight; | ||
+ | screenX2 = parseInt(screenX/ | ||
+ | docHeight = document.body.offsetHeight; | ||
+ | }; | ||
+ | |||
+ | this.freeze = function() { | ||
+ | // pause animation | ||
+ | if (!storm.disabled) { | ||
+ | storm.disabled = 1; | ||
+ | } else { | ||
+ | return false; | ||
+ | } | ||
+ | storm.timer = null; | ||
+ | }; | ||
+ | |||
+ | this.resume = function() { | ||
+ | if (storm.disabled) { | ||
+ | | ||
+ | } else { | ||
+ | return false; | ||
+ | } | ||
+ | storm.timerInit(); | ||
+ | }; | ||
+ | |||
+ | this.toggleSnow = function() { | ||
+ | if (!storm.flakes.length) { | ||
+ | // first run | ||
+ | storm.start(); | ||
+ | } else { | ||
+ | storm.active = !storm.active; | ||
+ | if (storm.active) { | ||
+ | storm.show(); | ||
+ | storm.resume(); | ||
+ | } else { | ||
+ | storm.stop(); | ||
+ | storm.freeze(); | ||
+ | } | ||
+ | } | ||
+ | }; | ||
+ | |||
+ | this.stop = function() { | ||
+ | var i; | ||
+ | this.freeze(); | ||
+ | for (i=0; i< | ||
+ | this.flakes[i].o.style.display = ' | ||
+ | } | ||
+ | storm.events.remove(window,' | ||
+ | storm.events.remove(window,' | ||
+ | if (storm.freezeOnBlur) { | ||
+ | if (isIE) { | ||
+ | storm.events.remove(document,' | ||
+ | storm.events.remove(document,' | ||
+ | } else { | ||
+ | storm.events.remove(window,' | ||
+ | storm.events.remove(window,' | ||
+ | } | ||
+ | } | ||
+ | }; | ||
+ | |||
+ | this.show = function() { | ||
+ | var i; | ||
+ | for (i=0; i< | ||
+ | this.flakes[i].o.style.display = ' | ||
+ | } | ||
+ | }; | ||
+ | |||
+ | this.SnowFlake = function(type, | ||
+ | var s = this; | ||
+ | this.type = type; | ||
+ | this.x = x||parseInt(rnd(screenX-20), | ||
+ | this.y = (!isNaN(y)? | ||
+ | this.vX = null; | ||
+ | this.vY = null; | ||
+ | this.vAmpTypes = [1, | ||
+ | this.vAmp = this.vAmpTypes[this.type] || 1; | ||
+ | this.melting = false; | ||
+ | this.meltFrameCount = storm.meltFrameCount; | ||
+ | this.meltFrames = storm.meltFrames; | ||
+ | this.meltFrame = 0; | ||
+ | this.twinkleFrame = 0; | ||
+ | this.active = 1; | ||
+ | this.fontSize = (10+(this.type/ | ||
+ | this.o = document.createElement(' | ||
+ | this.o.innerHTML = storm.snowCharacter; | ||
+ | if (storm.className) { | ||
+ | this.o.setAttribute(' | ||
+ | } | ||
+ | this.o.style.color = storm.snowColor; | ||
+ | this.o.style.position = (fixedForEverything?' | ||
+ | if (storm.useGPU && features.transform.prop) { | ||
+ | // GPU-accelerated snow. | ||
+ | this.o.style[features.transform.prop] = ' | ||
+ | } | ||
+ | this.o.style.width = storm.flakeWidth+' | ||
+ | this.o.style.height = storm.flakeHeight+' | ||
+ | this.o.style.fontFamily = ' | ||
+ | this.o.style.cursor = ' | ||
+ | this.o.style.overflow = ' | ||
+ | this.o.style.fontWeight = ' | ||
+ | this.o.style.zIndex = storm.zIndex; | ||
+ | docFrag.appendChild(this.o); | ||
+ | |||
+ | this.refresh = function() { | ||
+ | if (isNaN(s.x) || isNaN(s.y)) { | ||
+ | // safety check | ||
+ | return false; | ||
+ | } | ||
+ | storm.setXY(s.o, | ||
+ | }; | ||
+ | |||
+ | this.stick = function() { | ||
+ | if (noFixed || (storm.targetElement !== document.documentElement && storm.targetElement !== document.body)) { | ||
+ | s.o.style.top = (screenY+scrollY-storm.flakeHeight)+' | ||
+ | } else if (storm.flakeBottom) { | ||
+ | s.o.style.top = storm.flakeBottom+' | ||
+ | } else { | ||
+ | s.o.style.display = ' | ||
+ | s.o.style.bottom = ' | ||
+ | s.o.style.position = ' | ||
+ | s.o.style.display = ' | ||
+ | } | ||
+ | }; | ||
+ | |||
+ | this.vCheck = function() { | ||
+ | if (s.vX>=0 && s.vX< | ||
+ | s.vX = 0.2; | ||
+ | } else if (s.vX<0 && s.vX> | ||
+ | s.vX = -0.2; | ||
+ | } | ||
+ | if (s.vY>=0 && s.vY< | ||
+ | s.vY = 0.2; | ||
+ | } | ||
+ | }; | ||
+ | |||
+ | this.move = function() { | ||
+ | var vX = s.vX*windOffset, | ||
+ | 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; | ||
+ | } | ||
+ | s.refresh(); | ||
+ | yDiff = screenY+scrollY-s.y+storm.flakeHeight; | ||
+ | if (yDiff< | ||
+ | s.active = 0; | ||
+ | if (storm.snowStick) { | ||
+ | s.stick(); | ||
+ | } else { | ||
+ | s.recycle(); | ||
+ | } | ||
+ | } else { | ||
+ | if (storm.useMeltEffect && s.active && s.type < 3 && !s.melting && Math.random()> | ||
+ | // ~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 ? ' | ||
+ | } 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, | ||
+ | s.vY = vRndY+rnd(storm.vMaxY*0.12, | ||
+ | }; | ||
+ | |||
+ | this.setOpacity = function(o, | ||
+ | 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.o.style.fontSize = s.fontSize-(s.fontSize*(s.meltFrame/ | ||
+ | s.o.style.lineHeight = storm.flakeHeight+2+(storm.flakeHeight*0.75*(s.meltFrame/ | ||
+ | s.meltFrame++; | ||
+ | } else { | ||
+ | s.recycle(); | ||
+ | } | ||
+ | } | ||
+ | }; | ||
+ | |||
+ | this.recycle = function() { | ||
+ | s.o.style.display = ' | ||
+ | s.o.style.position = (fixedForEverything?' | ||
+ | s.o.style.bottom = ' | ||
+ | s.setVelocities(); | ||
+ | s.vCheck(); | ||
+ | s.meltFrame = 0; | ||
+ | s.melting = false; | ||
+ | s.setOpacity(s.o, | ||
+ | s.o.style.padding = ' | ||
+ | s.o.style.margin = ' | ||
+ | s.o.style.fontSize = s.fontSize+' | ||
+ | s.o.style.lineHeight = (storm.flakeHeight+2)+' | ||
+ | s.o.style.textAlign = ' | ||
+ | s.o.style.verticalAlign = ' | ||
+ | s.x = parseInt(rnd(screenX-storm.flakeWidth-20), | ||
+ | s.y = parseInt(rnd(screenY)*-1, | ||
+ | s.refresh(); | ||
+ | s.o.style.display = ' | ||
+ | s.active = 1; | ||
+ | }; | ||
+ | |||
+ | this.recycle(); | ||
+ | this.refresh(); | ||
+ | |||
+ | }; | ||
+ | |||
+ | this.snow = function() { | ||
+ | var active = 0, flake = null, i, j; | ||
+ | for (i=0, j=storm.flakes.length; | ||
+ | if (storm.flakes[i].active === 1) { | ||
+ | storm.flakes[i].move(); | ||
+ | active++; | ||
+ | } | ||
+ | if (storm.flakes[i].melting) { | ||
+ | storm.flakes[i].melt(); | ||
+ | } | ||
+ | } | ||
+ | if (active< | ||
+ | flake = storm.flakes[parseInt(rnd(storm.flakes.length), | ||
+ | if (flake.active === 0) { | ||
+ | flake.melting = true; | ||
+ | } | ||
+ | } | ||
+ | if (storm.timer) { | ||
+ | features.getAnimationFrame(storm.snow); | ||
+ | } | ||
+ | }; | ||
+ | |||
+ | this.mouseMove = function(e) { | ||
+ | if (!storm.followMouse) { | ||
+ | return true; | ||
+ | } | ||
+ | var x = parseInt(e.clientX, | ||
+ | if (x< | ||
+ | windOffset = -windMultiplier+(x/ | ||
+ | } else { | ||
+ | x -= screenX2; | ||
+ | windOffset = (x/ | ||
+ | } | ||
+ | }; | ||
+ | |||
+ | this.createSnow = function(limit, | ||
+ | var i; | ||
+ | for (i=0; i<limit; i++) { | ||
+ | storm.flakes[storm.flakes.length] = new storm.SnowFlake(parseInt(rnd(flakeTypes), | ||
+ | if (allowInactive || i> | ||
+ | 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< | ||
+ | storm.meltFrames.push(1-(i/ | ||
+ | } | ||
+ | storm.randomizeWind(); | ||
+ | storm.createSnow(storm.flakesMax); | ||
+ | storm.events.add(window,' | ||
+ | storm.events.add(window,' | ||
+ | if (storm.freezeOnBlur) { | ||
+ | if (isIE) { | ||
+ | storm.events.add(document,' | ||
+ | storm.events.add(document,' | ||
+ | } else { | ||
+ | storm.events.add(window,' | ||
+ | storm.events.add(window,' | ||
+ | } | ||
+ | } | ||
+ | storm.resizeHandler(); | ||
+ | storm.scrollHandler(); | ||
+ | if (storm.followMouse) { | ||
+ | storm.events.add(isIE? | ||
+ | } | ||
+ | storm.animationInterval = Math.max(20, | ||
+ | storm.timerInit(); | ||
+ | }; | ||
+ | |||
+ | this.start = function(bFromOnLoad) { | ||
+ | if (!didInit) { | ||
+ | didInit = true; | ||
+ | } else if (bFromOnLoad) { | ||
+ | // already loaded and running | ||
+ | return true; | ||
+ | } | ||
+ | if (typeof storm.targetElement === ' | ||
+ | var targetID = storm.targetElement; | ||
+ | storm.targetElement = document.getElementById(targetID); | ||
+ | if (!storm.targetElement) { | ||
+ | throw new Error(' | ||
+ | } | ||
+ | } | ||
+ | if (!storm.targetElement) { | ||
+ | storm.targetElement = (document.body || document.documentElement); | ||
+ | } | ||
+ | if (storm.targetElement !== document.documentElement && storm.targetElement !== document.body) { | ||
+ | // re-map handler to get element instead of screen dimensions | ||
+ | storm.resizeHandler = storm.resizeHandlerAlt; | ||
+ | //and force-enable pixel positioning | ||
+ | storm.usePixelPosition = true; | ||
+ | } | ||
+ | storm.resizeHandler(); | ||
+ | storm.usePositionFixed = (storm.usePositionFixed && !noFixed && !storm.flakeBottom); | ||
+ | if (window.getComputedStyle) { | ||
+ | // attempt to determine if body or user-specified snow parent element is relatlively-positioned. | ||
+ | try { | ||
+ | targetElementIsRelative = (window.getComputedStyle(storm.targetElement, | ||
+ | } catch(e) { | ||
+ | // oh well | ||
+ | targetElementIsRelative = false; | ||
+ | } | ||
+ | } | ||
+ | fixedForEverything = storm.usePositionFixed; | ||
+ | if (screenX && screenY && !storm.disabled) { | ||
+ | storm.init(); | ||
+ | storm.active = true; | ||
+ | } | ||
+ | }; | ||
+ | |||
+ | function doDelayedStart() { | ||
+ | window.setTimeout(function() { | ||
+ | storm.start(true); | ||
+ | }, 20); | ||
+ | // event cleanup | ||
+ | storm.events.remove(isIE? | ||
+ | } | ||
+ | |||
+ | function doStart() { | ||
+ | if (!storm.excludeMobile || !isMobile) { | ||
+ | doDelayedStart(); | ||
+ | } | ||
+ | // event cleanup | ||
+ | storm.events.remove(window, | ||
+ | } | ||
+ | |||
+ | // hooks for starting the snow | ||
+ | if (storm.autoStart) { | ||
+ | storm.events.add(window, | ||
+ | } | ||
+ | |||
+ | return this; | ||
+ | |||
+ | }(window, document)); | ||
+ | </ | ||
+ | ++++ | ||
+ | ===== Полезные команды ===== | ||
+ | Включить превью офисных форматов: | ||
+ | <code bash> | ||
+ | nano / | ||
+ | </ | ||
+ | < | ||
+ | ' | ||
+ | </ | ||
+ | |||
+ | Перемещение файлов от одного пользователя к другому | ||
+ | <code bash> | ||
+ | sudo -u www-data php / | ||
+ | </ | ||
+ | https:// | ||
+ | |||
+ | Удалить пользователя username: | ||
+ | <code bash> | ||
+ | sudo -u www-data php / | ||
+ | </ | ||
+ | |||
+ | Почистить корзину у всех пользователей | ||
+ | <code bash> | ||
+ | sudo -u www-data php / | ||
+ | </ | ||
+ | ===== Решение проблем ===== | ||
+ | ==== Failed to connect to www.nextcloud.com ==== | ||
+ | В логах куча сообщений: | ||
+ | // | ||
+ | |||
+ | Сайт nexcloud.com реально бывает недоступен. Workaround - отключить проверку на наличие интернета: | ||
+ | <code bash> | ||
+ | echo "' | ||
+ | </ | ||
+ | Или не обращать внимания. | ||
+ | |||
+ | ==== 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:// | ||
+ | |||
+ | ==== Поломались " | ||
+ | Обновить файл .htaccess: | ||
+ | <code bash> | ||
+ | sudo -u www-data php / | ||
+ | </ | ||
+ | https:// | ||
+ | |||
+ | ==== Specified key was too long; max key length is 767 bytes ==== | ||
+ | При обновлении Nexcloud ошибка: | ||
+ | <color # | ||
+ | |||
+ | Решение: | ||
+ | <code bash> | ||
+ | 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 / | ||
+ | sudo -u www-data php / | ||
+ | </ | ||
+ | |||
+ | ==== The database is missing some indexes ==== | ||
+ | Проверка в админке пишет: The database is missing some indexes | ||
+ | |||
+ | Решение: | ||
+ | <code bash> | ||
+ | sudo -u www-data php / | ||
+ | # В докере: | ||
+ | docker exec -u www-data nc php occ db: | ||
+ | </ | ||
+ | |||
+ | ==== Обновление прошло неуспешно, | ||
+ | Отключить регулярную задачу в crontab.\\ | ||
+ | <code bash> | ||
+ | # Проверить, | ||
+ | php -i | grep apc.enable | ||
+ | apc.enable_cli => Off => Off | ||
+ | apc.enabled => On => On | ||
+ | # Если нет, то включить | ||
+ | echo " | ||
+ | # Перейти в каталог NC (обязательно!) и запустить апгрейд заново | ||
+ | cd / | ||
+ | sudo -u www-data php occ upgrade | ||
+ | </ | ||
+ | Включить регулярную задачу в crontab. | ||
+ | |||
+ | https:// | ||
+ | |||
+ | ==== " | ||
+ | <code bash> | ||
+ | # Для Alpine. Для контейнера добавить этот пакет в докерфайл. | ||
+ | apk add imagemagick-svg | ||
+ | # Старое решение | ||
+ | apt-get install libmagickcore-6.q16-6-extra | ||
+ | </ | ||
+ | https:// | ||
+ | https:// | ||
+ | |||
+ | |||
+ | |||
+ | ==== Your installation has no default phone region set ==== | ||
+ | <code php> | ||
+ | sudo -u www-data php / | ||
+ | # Докер | ||
+ | docker exec -u www-data nc php occ config: | ||
+ | </ | ||
+ | |||
+ | ==== Last background job execution ran 15 hours ago. Something seems wrong ==== | ||
+ | Запустить принудительно | ||
+ | <code bash> | ||
+ | sudo -u www-data php -f / | ||
+ | </ | ||
+ | |||
+ | ==== PHP Fatal error: | ||
+ | При выполнении PHP cron. | ||
+ | |||
+ | I had APCu activated in the nextcloud config.php. It seems I didn’t have '' | ||
+ | |||
+ | https:// | ||
+ | |||
+ | ==== 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. | ||
+ | <code bash> | ||
+ | docker exec -uwww-data nc-php php / | ||
+ | # docker exec -uwww-data nc-php php / | ||
+ | |||
+ | # Сейчас NC не ориентируется на DNS-имя прокси, | ||
+ | # Решение - добавить подсеть, | ||
+ | docker exec -uwww-data nc-php php / | ||
+ | # docker exec -uwww-data nc-php php / | ||
+ | </ | ||
+ | https:// | ||
+ | https:// | ||
+ | |||
+ | ==== Docker - exec: " | ||
+ | После обновления контейнера PHP с версии 7.4 на 8.0 при попытке выполнить команду php occ внутри контейнера выдаётся ошибка: | ||
+ | OCI runtime exec failed: exec failed: unable to start container process: exec: " | ||
+ | |||
+ | Проблема в том, что в дистрибутиве Alpine автоматически не создаётся символическая ссылка php8 -> php, т. к. для php8 не готовы все пакеты. Решение: | ||
+ | <code bash> | ||
+ | ln -sf / | ||
+ | </ | ||
+ | |||
+ | ==== The __Host prefix mitigates cookie injection ==== | ||
+ | https:// | ||
+ | |||
+ | Предположительное решение: | ||
+ | |||
+ | ==== Клиент виснет после начала синхронизации ==== | ||
+ | Ситуация - виснет клиент практически сразу после запуска, | ||
+ | |||
+ | Решение: | ||
+ | <code powershell> | ||
+ | # убить процесс | ||
+ | Get-Process nextcloud |kill | ||
+ | # запустить синхронизацию с помощью nextcloudcmd | ||
+ | " | ||
+ | " | ||
+ | </ | ||
+ | Затем запустить клиента, | ||
+ | |||
+ | https:// | ||
+ | |||
+ | ==== Операция не разрешена модулем контроля доступа ==== | ||
+ | Operation is blocked by access control | ||
+ | |||
+ | Симптом - маленькие файлы грузятся, | ||
+ | |||
+ | https:// | ||
+ | |||
+ | ==== X-Robots-Tag HTTP header is not set ==== | ||
+ | <color # | ||
+ | |||
+ | Поменять опцию в '' | ||
+ | <code bash> | ||
+ | add_header X-Robots-Tag | ||
+ | # на | ||
+ | add_header X-Robots-Tag | ||
+ | </ | ||
+ | |||
+ | Because “none” is indeed equivalent to “noindex, nofollow” for Google, but seems to be not supported by Bing and probably other search engines. (https:// | ||
+ | |||
+ | ==== OPcache interned strings buffer is nearly full ==== | ||
+ | <color # | ||
+ | |||
+ | <code bash> | ||
+ | sed -i '/ | ||
+ | systemctl restart php-fpm | ||
+ | </ | ||
+ | |||
+ | ==== OnlyOffice не работает после обновления Nextcloud на версию 28 ==== | ||
+ | В логе | ||
+ | < | ||
+ | Exception array_merge(): | ||
+ | </ | ||
+ | Временное решение: | ||
+ | < | ||
+ | return array_merge($mergeWith, | ||
+ | # заменить на | ||
+ | return array_merge($mergeWith, | ||
+ | </ | ||
+ | <code bash> | ||
+ | sed -i ' | ||
+ | </ | ||
+ | |||
+ | ==== Could not check for JavaScript support ==== | ||
+ | <color # | ||
+ | |||
+ | https:// | ||
+ | |||
+ | ==== Server has no maintenance window start time configured ==== | ||
+ | <color # | ||
+ | |||
+ | A value of 1 e.g. will only run these background jobs between 01:00am UTC and 05:00am UTC. | ||
+ | <code php> | ||
+ | ' | ||
+ | </ | ||
+ | https:// | ||
+ | https:// | ||
+ | |||
+ | ==== 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, всё начинает нормально работать. | ||
+ | <code bash> | ||
+ | --entryPoints.web.transport.respondingTimeouts.readTimeout=0s | ||
+ | # Либо добавить переменную в Докере | ||
+ | TRAEFIK_ENTRYPOINTS_WEB_TRANSPORT_RESPONDINGTIMEOUTS_READTIMEOUT: | ||
+ | </ | ||
+ | https:// | ||
+ | |||
+ | ==== Incorrect row format found in your database ==== | ||
+ | После обновления на версию 31 | ||
+ | |||
+ | <color # | ||
+ | |||
+ | <code bash> | ||
+ | #!/bin/bash | ||
+ | |||
+ | DB_USER=' | ||
+ | DB_PASS=' | ||
+ | DB_NAME=' | ||
+ | |||
+ | mysql -u " | ||
+ | SELECT CONCAT(' | ||
+ | FROM INFORMATION_SCHEMA.TABLES | ||
+ | WHERE TABLE_SCHEMA = ' | ||
+ | AND ENGINE = ' | ||
+ | " -B -N | while read -r sql; do | ||
+ | mysql -u " | ||
+ | done | ||
+ | </ | ||
+ | https:// | ||
+ | |||
+ | ==== High-performance backend (HPB) ==== | ||
+ | <color # | ||
+ | |||
+ | При домашнем использовании проще отключить это предупреждение в настройках Talk, т. к. вряд ли там будет больше 2-3 участников. | ||
+ | |||
+ | В другом случае https:// | ||
+ | |||
+ | ===== Ссылки ===== | ||
+ | [[https:// | ||
+ | [[https:// | ||
+ | [[https:// | ||
+ | [[https:// | ||
+ | |||
+ | https:// |