Давно хотел написать целостный туториал по поднятию Owncloud в условиях домашнего сервера или небольшой компании до 500 пользователей. Owncloud — это прекрасный open-source проект, который позволяет на собственной инфраструктуре поднять свой вариант сервера синхронизации. По возможностям очень похож на Dropbox, а в чем-то его и превосходит. Огромный плюс — отсутствие ограничений по объемам хранения, полный контроль над сервером. Минусы тоже очевидны: вам самим придется следить за всем этим безобразием и беспокоиться о надежности сервера, валяющегося на антресолях или в шкафу.
Совсем недавно мне подвернулась задача по развертыванию Owncloud в домашне-боевых условиях. Я честно отработал свои два литра кошерного русского имперского стаута и решил поделиться своим опытом, собрав все воедино. Итак, сегодня мы рассмотрим:
- Развертывание актуального LEMP-stack
- HTTPS. Let's Encrypt для Nginx с автоматическим обновлением сертификата
- Конфигурирование Nginx для Owncloud
- Кэширование php-apcu
- Подключение внешнего основного хранилища по NFS
Стартовый комплект
Операционная система под наш сервер — Ubuntu 16.04.1 Server (torrent). Оптимальный вариант — виртуальная машина. Это довольно удачное решение благодаря легкости миграции, возможности динамического выделения ресурсов, снапшотов и прочих плюшек. Размер виртуальной машины — 10-15 ГБ. Этого более чем достаточно под систему.
Внешнее хранилище (каталог data для owncloud), где будут храниться все ваши данные. Размер — в зависимости от ваших потребностей. Я бы рекомендовал рассматривать вариант от 100 ГБ. Разделение хранилища и основной логики сервера дает большую гибкость конфигурации. В данном случае — SSD для системы и HDD от NAS для данных. При подключении внешнего раздела с данными появляется гибкость в плане миграции и возможность нарастить скорость или объем, если вдруг потребуется.
Домен и внешний ip-адрес — в условиях умирающего пула свободных ipv4 адресов провайдеры все реже отдают просто так белый внешний адрес. Если у вас серый адрес, то тут уже мало, что можно сделать. Только пробрасывать VPN-туннель на свою
Домен отдают 4-го уровня. Обычный StartSSL и другие сертификационные центры не станут с вами работать, если вы не владеете 2 уровнем. Раньше это приводило к использованию самоподписанного сертификата, на который ругался браузер. Теперь появился Let's Encrypt, который проблему решает.
Есть и альтернативные варианты, которые хорошо описаны в публикации Домашний хостинг сайтов с динамическим IP пользователем spectreob.
Развертываем LEMP
Начинать, пожалуй, стоит с установки наиболее привычных утилит для работы: htop, iotop, iftop, mc. Затем приступаем к самому LEMP — Linux, Nginx (его произносят как Engine X), MySQL/MariaDB и PHP. Linux у нас уже есть. Почему Ubuntu 16.04, а не, скажем, Debian или CentOS? Я не люблю rpm, и с Ubuntu проще в плане репозиториев со свежими версиями софта. Очень не люблю практику «make install» на боевых серверах. Все же более оптимальным является путь использования пакетного менеджера. Этого принципа и будем придерживаться.
Устанавливаем nginx, сконфигурируем позже:
sudo apt-get install nginx
Развертываем MariDB (актуальный форк MySQL) и проверяем работоспособность сервиса:
sudo apt-get install mariadb-server mariadb-client
sudo systemctl status mysql.service
Выполняем hardening-процедуру, отключая тестовые базы и прочие потенциальные дыры в защите:
sudo mysql_secure_installation
Будет запущен диалог, в котором надо будет ответить на серию вопросов. В этом же диалоге мы задаем пароль для root. Он потребуется позже, когда будем создавать базу для owncloud.
Устанавливаем PHP7.0, php-fpm и модули, необходимые для работы owncloud, с сопутствующими сервисами:
sudo apt-get install php7.0 php7.0-mysql php7.0-fpm php7.0-gd php7.0-json php7.0-curl php7.0-zip php7.0-xml php7.0-mbstring
Также для работы Owncloud требуется отредактировать переменные окружения:
sudo nano /etc/php/7.0/fpm/pool.d/www.conf
Необходимо раскомментировать следующие строки:
env[HOSTNAME] = $HOSTNAME
env[PATH] = /usr/local/bin:/usr/bin:/bin
env[TMP] = /tmp
env[TMPDIR] = /tmp
env[TEMP] = /tmp
Настраиваем Let's Encrypt и конфигурируем Nginx
Let's Encrypt — это некоммерческая инициатива, предоставляющая бесплатный, автоматизированный и открытый центр сертификации. За что им огромное спасибо. Вероятно, сертификационные центры, которые торгуют, по сути, своей репутацией, теперь будут вынуждены получать основную прибыль из сертификатов высокого класса — Organization Validation (OV) или Extended Validation (EV). Такой тип сертификата доступен только для юридических лиц и подтверждает факт существования условного ООО «Рога и Копыта». При этом проверяется владение доменом, сама компания, нотариально заверенные документы и другие нюансы.
Для личного использования нам вполне будет достаточно Domain Validation сертификата от Let's Encrypt. Этот вариант по сути лишь удостоверяет тот факт, что вы соединились именно с доменом example.com. И заодно защитит нас от Man-in-the-Middle атак, инжекции всякой дряни на целевую страницу (передаю привет MosMetro Wi-Fi и сотовым операторам) и перехвата паролей при использовании общественных сетей. Идеальный вариант для собственного Owncloud. Почему не использовать самоподписанный сертификат?
В Owncloud есть отличная функция «share link», которая позволяет передать человеку ссылку на файл или каталог. Очень удобно, когда внезапно нужно передать что-то весом в 50 ГБ, а более привычные Dropbox и Google Drive бесплатно такое не позволяют. Вы точно не хотите объяснять бухгалтеру Олимпиаде Сигизмундовне, почему ее браузер пылает красным и кричит, что ее взломали пакистанские хакеры все плохо из-за невалидного сертификата. Тем более, что все весьма просто.
Основная идея Let's Encrypt — выдача автоматически сертификаты с коротким сроком действия — 90 дней. По мнению авторов проекта, это увеличит безопасность благодаря автоматическому выведению из оборота скомпрометированых сертификатов. Для валидации домена сервис предлагает certbot-auto с несколькими сценариями работы:
- Apache — автоматически получает и устанавливает сертификат для Apache 2.4. Использует 443 порт
- Nginx — автоматически получает и устанавливает сертификат для Nginx. Альфа версия, для продакшена рано. Использует 443 порт
- webroot — создает в корневом каталоге действующего сервера файлы необходимые для валидации домена. Использует 80 порт
- standalone — поднимает автономный сервер, который отвечает на необходимые запросы извне для валидации. Использует 80 или 443 порт. Для систем, которые не имеют действующего веб-сервера и других случаев.
- manual — полностью ручной режим, требующий ручной копипасты. Применяется в том случае, когда вы генерируете ключи не на целевой машине. Например, для роутера.
В результате мы имеем хороший универсальный набор для разных сценариев использования, включая ситуации, когда у вас нет полного контроля на сервером. Автоматическую установку сертификата в Nginx мы не будем использовать из-за ее альфа статуса, а редактирование конфига рабочего веб-сервера — процесс крайне интимный. Очень не хочется столкнуться с кривой работой не отлаженного скрипта. Тем не менее, процесс получения сертификата мы автоматизируем.
Для начала выкачаем и установим последнюю версию certbot:
cd /usr/local/sbin
sudo wget https://dl.eff.org/certbot-auto
sudo chmod a+x /usr/local/sbin/certbot-auto
Редактируем конфиг nginx и разрешаем доступ к тому каталогу, в который будет писать webroot вариант certbot'а:
sudo nano /etc/nginx/sites-available/default
Добавляем строки:
location ~ /.well-known {
allow all;
}
Перезапускаем сервис nginx:
sudo service nginx restart
Теперь можно запустить certbot и сгенерировать сертификаты для нашего домена. В нашем конкретном случае это домен аж четвертого уровня от Mikrotik DDNS. Никто другой валидные для браузеров сертификаты вам не подпишет даже для третьего.
sudo certbot-auto certonly -a webroot --webroot-path=/usr/share/nginx/html -d example.sn.mynetname.net
В диалоговом окне нужно будет ввести адрес электронной почты и согласиться с условиями использования:
Certbot складывает актуальные версии сертификатов в каталог /etc/letsencrypt/live/, создавая симлинки. Внутри будут лежать файлы:
- cert.pem: сертификат вашего домена
- chain.pem: chain сертификат Let's Encrypt
- fullchain.pem: комбинированный сертификат из cert.pem и chain.pem
- privkey.pem: приватный ключ вашего сертификата
Генерируем ключ Диффи — Хеллмана:
sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048
Отлично. Теперь, прописав в конфиге Nginx ссылку на /etc/letsencrypt/live/, мы будем иметь всегда актуальную версию. Создаем новый конфиг для нашего домена:
sudo nano /etc/nginx/sites-available/example.sn.mynetname.net
Готовый конфиг с оптимизациями, которые рекомендует мануал owncloud. 80 порт автоматически редиректит на 443:
upstream php-handler {
#server 127.0.0.1:9000;
server unix:/run/php/php7.0-fpm.sock;
}
#Redirect from 80 to 443
server {
listen 80;
server_name example.sn.mynetname.net;
return 301 https://$host$request_uri;
}
# HTTPS
server {
listen 443 ssl;
server_name example.sn.mynetname.net;
ssl_certificate /etc/letsencrypt/live/example.sn.mynetname.net/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.sn.mynetname.net/privkey.pem;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_dhparam /etc/ssl/certs/dhparam.pem;
ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_stapling on;
ssl_stapling_verify on;
add_header Strict-Transport-Security max-age=15552001;
add_header Cache-Control "public, max-age=7200";
# Add headers to serve security related headers
add_header X-Content-Type-Options nosniff;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header X-Robots-Tag none;
add_header "X-Download-Options" "noopen";
add_header "X-Permitted-Cross-Domain-Policies" "none";
root /var/www/;
rewrite ^/.well-known/carddav /remote.php/carddav/ permanent;
rewrite ^/.well-known/caldav /remote.php/caldav/ permanent;
# Add index.php to the list if you are using PHP
index index.html index.htm index.nginx-debian.html;
location ~ /.well-known {
allow all;
}
location / {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
try_files $uri $uri/ =404;
}
location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}
location ~ ^/(?:.htaccess|data|config|db_structure.xml|README){
deny all;
}
location ~ ^/(build|tests|config|lib|3rdparty|templates|data)/ {
deny all;
}
location ~ ^/(?:.|autotest|occ|issue|indie|db_|console) {
deny all;
}
location ~ .php(?:$|/) {
fastcgi_split_path_info ^(.+.php)(/.+)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param HTTPS on;
fastcgi_param modHeadersAvailable true; #Avoid sending the security headers twice
fastcgi_pass php-handler;
fastcgi_intercept_errors on;
}
}
Приведенный конфиг дает оценку «A» на https://www.ssllabs.com. Конечно, если вам нужна совместимость со старыми версиями Java, Windows XP и тому подобным, придется разрешить некоторые потенциально небезопасные протоколы.
Автоматизируем обновление сертификата
Проверяем обновление сертификата:
sudo certbot-auto renew
При запуске этой команды certbot свяжется с серверами EFF и попытается обновить свою версию, если это возможно, а затем и сертификаты. Причем не только на все доступные домены. Очень удобно. Если срок смены сертификата не подошел, то ничего не произойдет, и скрипт об этом сообщит.
-------------------------------------------------------------------------------
Processing /etc/letsencrypt/renewal/example.sn.mynetname.net.conf
-------------------------------------------------------------------------------
Cert not yet due for renewal
The following certs are not due for renewal yet:
/etc/letsencrypt/live/example.sn.mynetname.net/fullchain.pem (skipped)
No renewals were attempted.
Теперь можно добавить регулярный запуск скрипта crontab:
sudo crontab -e
Внутрь добавляем регулярную задачу по обновлению сертификатов и их перезаливке в nginx:
30 2 * * 1 /usr/local/sbin/certbot-auto renew >> /var/log/le-renew.log
35 2 * * 1 /etc/init.d/nginx reload
Активируем наш сайт:
sudo ln -s /etc/nginx/sites-available/418402b5554f.sn.mynetname.net /etc/nginx/sites-enabled/
Установка Owncloud
Есть несколько вариантов, но наиболее предпочтительным в большинстве случаев является установка из репозитория. Пусть у пакетного менеджера голова болит по поводу обновлений. Главное, не забывать делать backup перед накатыванием новых пакетов. Иногда бывают неприятные сюрпризы. Для начала необходимо добавить GPG-ключ:
wget -nv https://download.owncloud.org/download/repositories/stable/Ubuntu_16.04/Release.key -O Release.key
sudo apt-key add - < Release.key
После этого добавляем репозиторий и устанавливаем пакет owncloud-files. Обычный пакет owncloud притянет по зависимости еще и Apache, а он нам не нужен.
sudo sh -c "echo 'deb http://download.owncloud.org/download/repositories/stable/Ubuntu_16.04/ /' > /etc/apt/sources.list.d/owncloud.list"
sudo apt-get update
sudo apt-get install owncloud-files
В результате, в /var/www/owncloud у вас развернется все необходимое. Так как Nginx считает корневым каталог /var/www, то доступ к сервису будет выглядеть примерно так: example.com/owncloud
Настраиваем MariaDB
Так как инсталляция у нас маленькая, то в тонкости оптимизации мы вдаваться не будем. Поэтому разворачиваем с более или менее дефолтным конфигом. Username и password подставьте те, которые будет использовать owncloud для доступа к своей базе данных.
sudo mysql -uroot -p
create database owncloud;
create user username@localhost identified by 'password';
grant all privileges on owncloud.* to username@localhost identified by 'password';
flush privileges;
exit;
Подключаем внешнее хранилище
Как я уже говорил раньше, мне кажется хорошей идеей разделять виртуальную машину с самой логикой сервиса и хранилище, куда будут падать синхронизированные данные. Здесь вы уже можете поступить по своему разумению. Можно не делать ничего, и тогда дефолтным хранилищем будет /var/www/owncloud/data. Можно поступить как я и создать каталог /mnt/data, куда через fstab будет монтироваться внешний том. Это может быть SSD/HDD, он может лежать локально, а может находиться на NAS-storage в этой же локальной сети. Не забудьте только протестировать скорость полученного гибрида. Это потенциально узкое место. В моем домашнем варианте это samba-сервер на хост-машине, кто-то может предпочесть NFS.
Дополнительное удобство такой гибридной конструкции — легкость переезда на более быстрые или емкие варианты при необходимости. Достаточно остановить сервисы и залить на новый подключаемый том все файлы из старого /mnt/data, после чего изменить точку монтирования в fstab и перезапустить сервис вновь. Вдруг вы решите перенести данные со старого HDD на SSD RAID?
Кэширование
Важный момент. Без memory caching owncloud может работать ощутимо задумчивее. Причем он непременно напомнит вам об этом на странице администратора. Выбор способа кэширования зависит от архитектуры системы. С рекомендациями от разработчиков вы можете ознакомиться тут. Если коротко, то для личного использования и небольших инсталляций рекомендуется использовать только APCu. Для малых организаций, при установке на один сервер — APCu для локального кэширования и Redis для file locking. Для установки на кластер в большой организации: Redis для всего, кроме локального кэширования.
Разработчики считают APCu наиболее быстрым вариантом для локального кэша. Если хватает оперативной памяти, то лучше использовать APCu для локального кэширования и Redis для file locking. Если памяти недостаточно, то рекомендуется использовать Redis и для того и другого.
В нашем варианте мы будем использовать только APCu. Установим соответствующий модуль для php:
sudo apt-get install php-apcu
Теперь будет достаточно просто добавить их в конфигурационный файл owncloud — config.php:
'memcache.local' => 'OCMemcacheAPCu',
Первый запуск нашего детища
Перезагружаем машину на всякий случай, чтобы перезапустить все сервисы. Заходим на example.com/owncloud и
внимательно жмем все кнопки без разбора заполняем строки админского аккаунта, паролей, расположения data католога (/mnt/data, как в этом руководстве), логина и пароля от owncloud-пользователя базы данных. Если все прошло нормально, то скоро вы загрузитесь в основное меню сервиса и сможете убедиться, что все нахрен сломано в порядке.
*Тысяча слонов
![Поднимаем Owncloud с нуля с динамическим IP и Let's Encrypt. Тысяча слонов!* - 12 image](https://www.pvsm.ru/images/2016/10/25/podnimaem-Owncloud-s-nulya-s-dinamicheskim-IP-i-Let's-Encrypt-tysyacha-slonov-12.jpg)
Но Достабль уже не слушал. Он указал на несколько прислоненных к стене дощечек.
— Что это такое? — спросил он.
— А это моя идея, — сказал Зильберкит. — Мы подумали, было бы проявлением… э-э… делового чутья, — он явно смаковал эти слова, как непривычное, но изысканное лакомство, — рассказывать людям о новых движущихся картинках, которые мы здесь производим.
Достабль подобрал одну из дощечек и, держа ее в вытянутой руке, осмотрел критическим оком. На ней значилось:
На будуюсчей ниделе мы пакажем
«ПЕЛИАС И МЕЛИСАНДРА»
Рамантическая Трогедия в 2 частях
Спасибо за внимание
— Угу, — произнес он без всякого выражения.
— Разве плохо? — глухо выговорил раздавленный Зильберкит. — Ну, это, ведь тут есть все, что необходимо знать зрителям.
— Разреши, — сказал Достабль, беря со стола Зильберкита кусочек мела.
Некоторое время он что-то торопливо царапал на обороте доски, а потом позволил прочитать написанное:
БОГИ И ЛЮДИ СКАЗАЛИ ЭТАМУ НИ БЫВАТЬ НО ОНИ НИЧИГО НИ ХАТЕЛИ СЛУШАТЬ
«ПЕЛИАС И МЕЛИСАНДРА»,
Истерия Запретной Люпви
Страсть Пабеждаит Прасранство и Время!
Тебя Натрясут
При Участии 1000 сланов!
Виктор и Зильберкит читали текст с настороженным вниманием. Так изучают обеденное меню на чужом языке. А язык и впрямь был чужим. Но что самое скверное, на вид он был прежним, родным.
— Ну, не знаю… — осторожно высказался Зильберкит. — Собственно говоря… Что уж там такого запретного… Э-э… Все это основано на реальной истории, только имена изменены. Я полагал, что картина будет полезна, так сказать, подрастающему поколению. Герои, извольте видеть, так никогда и не встретились — вот ведь в чем трагедия. Все это, э-э… очень-очень грустно. — Он посмотрел на дощечку. — Хотя, с другой стороны, в этом несомненно что-то есть. Э-э… — Он явно был чем-то обеспокоен. — Но я, по правде сказать, не помню никаких слонов. — Голос его прозвучал крайне виновато. — В день кликов я был на работе целый день, но совершенно не помню тысячи слонов, хотя наверняка заметил бы их.
Достабль сверлил его немигающим взором. Откуда взялись слоны, он и сам не знал, однако каждое новое мыслительное усилие одаривало его очередным, весьма определенным представлением о том, как следует производить картины. Тысяча слонов — для начала это совсем неплохо.
Спасибо всем дочитавшим до конца эту простыню. Мне хотелось описать максимально полно все детали, чтобы не приходилось рыться по разным, часто противоречивым источникам. Я не исключаю, что мог где-то допустить опечатки или неточности, хотя и проверил все дважды. Буду очень благодарен тыканью носом в ошибки.
Автор: Meklon