Поднимаем Owncloud с нуля с динамическим IP и Let's Encrypt. Тысяча слонов!*
![630c841f52aa4d9dbaf064d0429b14ac.jpg](https://habrastorage.org/files/630/c84/1f5/630c841f52aa4d9dbaf064d0429b14ac.jpg)
Давно хотел написать целостный туториал по поднятию 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-туннель на свою VPS с белым IP и плясать оттуда. Но иногда провайдеры отдают вполне белые адреса, но не статику, а динамику. Причем адрес может меняться просто по велению левой пятки, сессия рваться в полночь, и абонент получает новый IP. В текущем кейсе стоит роутер MikroTik, который умеет бесплатный динамический DNS, начиная с RouterOS v6.14. Находится эта радость в разделе IP/Cloud. После подключения функции роутер получает доменное имя вида 123456b7890f.sn.mynetname.net. Домен этот всегда указывает на ipv4 адрес, выданный провайдером.
![image](https://habrastorage.org/getpro/habr/post_images/fa0/fdf/d7c/fa0fdfd7c68a0546336300f70b497f97.jpg)
Домен отдают 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
![image](https://habrastorage.org/getpro/habr/post_images/99a/ca8/9f3/99aca89f32c663b0d64117ab4764ef1b.png)
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
В диалоговом окне нужно будет ввести адрес электронной почты и согласиться с условиями использования:
![image](https://habrastorage.org/getpro/habr/post_images/62d/58b/f21/62d58bf2179b7fa8bac6cd3abb7d308d.png)
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;
}
}
![e0efeed089cf4506afafe377f6c7e52e.png](https://habrastorage.org/files/e0e/fee/d08/e0efeed089cf4506afafe377f6c7e52e.png)
Приведенный конфиг дает оценку «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
![image](https://habrastorage.org/getpro/habr/comment_images/bea/ef7/eea/beaef7eea4d08c19d85f2446353f6366.png)
Есть несколько вариантов, но наиболее предпочтительным в большинстве случаев является установка из репозитория. Пусть у пакетного менеджера голова болит по поводу обновлений. Главное, не забывать делать 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?
Кэширование
![image](https://media.licdn.com/mpr/mpr/shrinknp_800_800/AAEAAQAAAAAAAAWoAAAAJGUxZjFkMDU3LTcxMjQtNDkxNS04ZjAwLTYzMjg2ZWIyNzY1Nw.png)
Важный момент. Без 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' => '\OC\Memcache\APCu',
Первый запуск нашего детища
![image](http://www.kinomania.ru/images/news/50465.jpg)
Перезагружаем машину на всякий случай, чтобы перезапустить все сервисы. Заходим на example.com/owncloud и
внимательно жмем все кнопки без разбора заполняем строки админского аккаунта, паролей, расположения data католога (/mnt/data, как в этом руководстве), логина и пароля от owncloud-пользователя базы данных. Если все прошло нормально, то скоро вы загрузитесь в основное меню сервиса и сможете убедиться, что все нахрен сломано в порядке.
*Тысяча слонов
![image](http://www.vokrug.tv/pic/person/6/e/d/d/medium_6eddc41652c77b77711aa71e6f2d8ff2.jpeg)
Но Достабль уже не слушал. Он указал на несколько прислоненных к стене дощечек.
— Что это такое? — спросил он.
— А это моя идея, — сказал Зильберкит. — Мы подумали, было бы проявлением… э-э… делового чутья, — он явно смаковал эти слова, как непривычное, но изысканное лакомство, — рассказывать людям о новых движущихся картинках, которые мы здесь производим.
Достабль подобрал одну из дощечек и, держа ее в вытянутой руке, осмотрел критическим оком. На ней значилось:
На будуюсчей ниделе мы пакажем
«ПЕЛИАС И МЕЛИСАНДРА»
Рамантическая Трогедия в 2 частях
Спасибо за внимание
— Угу, — произнес он без всякого выражения.
— Разве плохо? — глухо выговорил раздавленный Зильберкит. — Ну, это, ведь тут есть все, что необходимо знать зрителям.
— Разреши, — сказал Достабль, беря со стола Зильберкита кусочек мела.
Некоторое время он что-то торопливо царапал на обороте доски, а потом позволил прочитать написанное:
БОГИ И ЛЮДИ СКАЗАЛИ ЭТАМУ НИ БЫВАТЬ НО ОНИ НИЧИГО НИ ХАТЕЛИ СЛУШАТЬ
«ПЕЛИАС И МЕЛИСАНДРА»,
Истерия Запретной Люпви
Страсть Пабеждаит Прасранство и Время!
Тебя Натрясут
При Участии 1000 сланов!
Виктор и Зильберкит читали текст с настороженным вниманием. Так изучают обеденное меню на чужом языке. А язык и впрямь был чужим. Но что самое скверное, на вид он был прежним, родным.
— Ну, не знаю… — осторожно высказался Зильберкит. — Собственно говоря… Что уж там такого запретного… Э-э… Все это основано на реальной истории, только имена изменены. Я полагал, что картина будет полезна, так сказать, подрастающему поколению. Герои, извольте видеть, так никогда и не встретились — вот ведь в чем трагедия. Все это, э-э… очень-очень грустно. — Он посмотрел на дощечку. — Хотя, с другой стороны, в этом несомненно что-то есть. Э-э… — Он явно был чем-то обеспокоен. — Но я, по правде сказать, не помню никаких слонов. — Голос его прозвучал крайне виновато. — В день кликов я был на работе целый день, но совершенно не помню тысячи слонов, хотя наверняка заметил бы их.
Достабль сверлил его немигающим взором. Откуда взялись слоны, он и сам не знал, однако каждое новое мыслительное усилие одаривало его очередным, весьма определенным представлением о том, как следует производить картины. Тысяча слонов — для начала это совсем неплохо.
Спасибо всем дочитавшим до конца эту простыню. Мне хотелось описать максимально полно все детали, чтобы не приходилось рыться по разным, часто противоречивым источникам. Я не исключаю, что мог где-то допустить опечатки или неточности, хотя и проверил все дважды. Буду очень благодарен тыканью носом в ошибки.
Комментарии (1)
25 октября 2016 в 11:51
0↑
↓
Кстати, был бы рад услышать об использовании в продакшене. У меня очень удачный опыт интеграции owncloud для нужд научной лаборатории. Особенно актуально, когда есть коллеги из других центров с которыми некого нужно обмениваться тяжелыми данными. При этом все плюсы контроля доступа к каталогам и версионирования.