NextCloud in the Clouds

Решил мигрировать приватное облако в облака… Ubuntu 16.04 LTS, NextCloud 13 + Apache 2.4, PHP 7.0, Redis, Let’s encrypt… поехали! Или полетели?

Старенькое облако-хранилище много лет исправно служило на выделенном сервере Ubuntu 14.x LTS. Данное облако предназначалось для прозрачного обмена документами внутри организации. В качестве решения в свое время был выбран ownCloud 9.

Прошли года, убунта состарилась, ownCloud 9 тоже, да и сервер, на котором это всё крутилось, тоже давно уже просился на профилактику/пенсию. В общем, всё шло к тому, что проще и быстрее поднять новый сервер на новом железе, чем заниматься старым.

Итак, в качестве “железа” были выбраны Hetzner и DigitalOcean (сразу два – чтобы сравнить). Почему в облако – причин несколько:

  • за время пользования ownCloud появились удаленные работники, для которых пришлось вывести сервер наружу (естественно, через DMZ);
  • облако сразу решает вопрос с доступностью и бекапированием (выделенный сервер тоже это всё имел, но у облака это по сути из коробки);
  • просто захотелось поиграться с Clouds %) и сравнить с выделенным сервером.

Почему Hetzner… да просто под НГ пришла от них реклама с вкусными ценами на облачные сервера. Если сравнивать с Digital Ocean – за те же деньги получаем в два раза больше ресурсов (ну или за те же ресурсы платим вдвое меньше). Почему не AWS? Первоначальный вариант сервера как раз на AWS EC2 и ставился (в рамках Free Tier), но даже грубая прикидка показала, что в лимиты Free Tier не впишемся, а платные варианты превысят прайс того же Digital Ocean как минимум в два раза (и то оптимистично учитывая, что на AWS тарифицируется почти любой чих).

На DigitalOcean у меня уже крутится пара серверов (почтовый и сервер, на котором вы сейчас читаете этот опус). Поэтому второй сервер был установлен на DO, для пробы взял самый маленький план.

0. Hetzner & DO Clouds

Активация аккаунта на Hetzner’е заняло чуть меньше месяца – там нужно подверждать себя сканом паспорта. На скане разрешено “замылить” все чувствительные данные, я по сути на скане загранпаспорта оставил только ФИО, страну и фото %) И…. неделя прошла, вторая пошла – не активируют. Посылаю запрос. Ответа нет… странно… а в спам ушли (надо же). Попросили по-новому выслать скан. Выслал тот же скан второй раз. И забыл. Через некоторое время смотрю – аккаунт таки активировали. Оплату, как и на DO, привязал к PayPal.

И понеслась. Первое – выбираем ОС и план. Я выбрал CX21 ( https://www.hetzner.com/cloud ), причем обошелся он всего в €4,9/мес (разная цена для разных регионов?). За эти деньги я получаю 2x vCPU / 4 GB RAM / 40 GB SSD / 20 TB traffic. Естественно, белый ip4, целая/64 подсеть ip6 и Reverse DNS.

Для сравнения – для почтового сервера на DigitalOcean я взял план 1x vCPU / 2 GB RAM / 50 GB SSD / 2 TB traffic за … $10/month. И это уже после предновогоднего сбрасывания цен. Как говорится, прочувствуйте разницу %).

Снапшот/бэкапы – в принципе аналогичны. Можно делать снапшоты (тут небольшой сюрприз – снапшот у Hetzner по размеру равен размеру диска, в отличии от DigitalOcean, где снапшотятся только полезные данные), стоимость – €0.01/GB/month у Hetzner по сравнению с $0.05/GB/month у DigitalOcean. В общем, если под завязку диск – то выгоднее таки Hetzner. В моем случае один снапшот обойдется в 40 центов  в месяц. Бекапы – каждодневные, 7 слотов.  то есть по сути под рукой имеем бекапы за последние 7 дней. На том же DigitalOcean бекапы делаются раз в неделю, хранятся месяц. Стоимость – 20% от тарифного плана там и там.

Выбор операционок у Hetzner в принципе хоть и куц, но вполне для меня достаточен – Ubuntu 16.04 LTS, Debian 9.3, CentOS 7.4, Fedore 27. Плюс при желании можно ставить из уже имеющегося набора ISO образов (включая те же “окошки”). Никаких дроплетов а-ля DigitalOcean / маркета а-ля AWS. Но мне и не нужно – привык ставить ручками. Доступ к консоли SSH с помощью ключа там и там. Я сгенерировал через puttyGen.

Аккаунт на DO уже имелся, поэтому просто создал новый дроплет, для пробы взял самый мелкий план (1x vCPU / 1 GB RAM / 25 GB SSD / 1TB traffic, 5$/month). Да, за тот же ценник возможности выглядят победнее, но… посмотрим. Белые ip4, ip6, есть Reverse DNS. При создании дроплета сразу указал полное имя сервера ( а-ля cloud.example.com ) – реверсивный DNS прописался сразу.

Итак, ставим. Установка абсолютно аналогично как для Hetzner, так и для DO.

1. Сервер Ubuntu 16.04 LTS

При создании сервера запрашиваются следующие данные (Hetzner Clouds):

LocationNuremberg / Falkenstein. Я выбрал Нюрнберг.

Image – Ubuntu 16.04 LTS

Type – есть два варианта, с локальным или сетевым хранилищем. Я выбрал локальное. Как я уже сказал, был выбран план CX21 (2x vCPU / 4 GB RAM / 40 GB SSD / 20 TB). В данном случае у меня решающим фактором был размер диска. 2 ЦПУ и 4Г памяти – как приятный бонус. 20TB трафика, как потом оказалось, скорее маркетинговый трюк.

Additional features – пока есть выбор только из одного пункта (user data). Ничего не выбрал.

SSH key – с помощью puttyGen сгенерировал RSA пару ключей, публичный закинул сюда.

Name – как Вы сервер назовете…. Помня про то, как именно на DigitalOcean делается реверсивный ДНС сразу вбил полное имя будущего сайта, например, cloud.example.com . И не ошибся – именно это имя было автоматически пробито во всех нужных местах свеженькой Ubuntu. Удобно.

Подождал создания виртуальной машины (1-2 минуты), зашел в консоль с помощью root/ключ. Проверил – hostname/hostname -f выдали правильное имя сервера, ip4 – белый. ip6 – первый из выделенной /64 подсети. Посему идем к регистратору и для cloud.example.com пробиваю ip4/ip6 адреса.

После создания виртуалки имеем девственно чистую инсталляцию, ничего лишнего, никаких LAMP/LEMP и тд.

Фаервол отключен.

Поэтому первым делом добавляю в список разрешенных избранные адреса (с которых я планирую заходить по ssh на этот сервер) и включаю фаервол:

ufw allow from a1.b1.c1.d1 to any port 22
ufw allow from a2.b2.c2.d2 to any port 22
ufw allow from a3.b3.c3.d3 to any port 22
ufw enable

Враг не пройдет.

Внимание! Если вобьете ошибочные ip-адреса и активируете фаервол – потеряете доступ к серверу… Так что семь раз перепроверяем и только тогда активируем.

Доступ остался? Ура, всё сделали правильно.

Проверяем/обновляем:

sudo apt update
sudo apt upgrade

Как ни странно, всё самое свежее. Даже уже накатаны обновления от Spectre/Meltdwon. Приятно удивили.

Так как под рутом постоянно работать не есть комиль-фо, создаем отдельного пользователя (пусть это будет blackvs) и добавляем его к sudoers:

adduser blackvs
usermod blackvs -aG sudo

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

2. Установка nextCloud

Тут всё просто – берем мануал и по нему.

Сперва пошел легким путем (через snap), всё прошло на ура, активировал Let’s encrypt и … обнаружил, что через snap установилась старая, 12-я, версия.

Если кому интересен этот вариант установки – проще всего пойти по мануалу от DigitalOcean – How To Install and Configure Nextcloud on Ubuntu 16.04

В принципе всё прозрачно, быстро, но.. 12-я версия (на данный момент). Поигрался, откатился на заблаговременно сделанный снапшот и пошел другим путем. Ручками.

2.1. Apache, PHP, MariaDb / MySQL

Сам nextCloud рекомендует Apache 2.4 / PHP 7.x . Ставим прямо по мануалу:

apt-get install apache2 mariadb-server libapache2-mod-php7.0
apt-get install php7.0-gd php7.0-json php7.0-mysql php7.0-curl php7.0-mbstring
apt-get install php7.0-intl php7.0-mcrypt php-imagick php7.0-xml php7.0-zip

В довесок еще ставим APCu, Redis (потом пригодится):

apt install php-apcu redis-server php-redis

Если ставили из под рута, то MySQL установится с пустым паролем. А это не есть хорошо. Ставим пароль на MySQL root :

mysqladmin -u root password VeryG00dPassw$rd

где VeryG00dPassw$rd – brute-force устойчивый пароль. Хоть мы и не будем выводить MariaDB наружу, но параноя есть параноя…

2.2. nextCloud – начальная установка

Далее идем на сервер nextCloud в раздел загрузок и скачиваем последнюю версию tar.bz2 архива и соответствующий ему md5 или sha256.

На данный момент это версия 13.0.0:

wget https://download.nextcloud.com/server/releases/nextcloud-13.0.0.tar.bz2
wget https://download.nextcloud.com/server/releases/nextcloud-13.0.0.tar.bz2.sha256
sha256sum -c nextcloud-13.0.0.tar.bz2.sha256 < nextcloud-13.0.0.tar.bz2

Если всё Ok, то в конце должны увидеть:

nextcloud-13.0.0.tar.bz2: OK

Распаковываем и перекидываем в /var/www :

tar -xjf nextcloud-13.0.0.tar.bz2
cp -r nextcloud /var/www
chown -R www-data:www-data /var/www/nextcloud/

В моем случае у меня будет единственный сервер, поэтому править буду сразу дефолтный конфиг (пока что только /etc/apache2/sites-available/000-default.conf):

<VirtualHost *:80>
 ServerName cloud.example.com
 ServerAdmin webmaster@localhost
 DocumentRoot /var/www/nextcloud
 <Directory /var/www/nextcloud/>
  Options +FollowSymlinks
  AllowOverride All
  <IfModule mod_dav.c>
   Dav off
  </IfModule>
  SetEnv HOME /var/www/nextcloud
  SetEnv HTTP_HOME /var/www/nextcloud
 </Directory>

 ErrorLog ${APACHE_LOG_DIR}/error.log
 CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

Если же вы будете сервер nextCloud ставить по соседству с существующим (или потом будет добавлен еще какой-то www сервер на эту же виртуалку) – то просто следуем строго по инструкциям из раздела Apache Web server configuration . Но лучше таки сервера не совмещать – в случае взлома одного www сервера злоумышленник получит доступ сразу ко всем остальным www серверам, которые разделяют одну виртуалку.

Такой еще момент. По умолчанию nextCloud использует вложенный фолдер (то есть /var/www/nextcloud/data ), то есть тогда эту папку нужно будет дополнительно защищать от несанкционированного доступа извне. Для этого нужно делать соответствующие настройки Apache. Но гораздо проще и эффективнее эту папку вывести за пределы www папки:

mkdir /var/www/nextcloud-data/  
sudo chown -R www-data:www-data /var/www/nextcloud-data/

Включаем необходимые модули:

a2enmod rewrite 
a2enmod headers 
a2enmod env 
a2enmod dir 
a2enmod mime

Проверяем конфиг на ошибки:

apache2ctl configtest

Если Syntax Ok – перезапускаем аппач:

service apache2 restart

Не забываем в фаерволе разрешить порты http/https:

ufw allow http ufw allow https

Если всё сделали правильно – то должны зайти на страницу http://cloud.example.com

Мы увидим мастер установки.

2.3. nextCloud – мастер установки

Сперва создадим пустую базу для nextCloud:

mysql -u root -p

Оно спросит пароль – вводим наш VeryG00dPassw$rd .

Далее выполним три команды (для этого придумываем еще один взломо-устойчивый пароль VeryG00dSecondPassw$rd):

CREATE USER nextcloud@localhost IDENTIFIED BY 'VeryG00dSecondPassw$rd'; 
CREATE DATABASE IF NOT EXISTS nextcloud; 
GRANT ALL PRIVILEGES ON nextcloud.* TO nextcloud@localhost; 
quit;

Так как сейчас сервер открыт для всех, долго не мешкаем и вводим следующие данные:

Admin account –  логин/пароль администратора (придумайте пароль устойчивый ко взлому!)
Data folder – тут пишем /var/www/nextcloud-data/ (иначе потом будет намного больше мороки).
Database user: nextcloud
Database password: VeryG00dSecondPassw$rd
Database name: nextcloud

Localhost не трогаем, так как БД и nextCloud на одном сервере.

Жмем Finish Setup.

Если всё Ок – то через минутку окажемся на нашем сервере.

Ура. Почти всё. Ну почти почти.

Заходим в Settings / Basic settings и видим ряд предупреждений:

Будем их устранять.

2.4. Redis как memory cache

Сам Redis мы уже установили. Проверяем, что у него в логе:

cat /var/log/redis/redis-server.log

У меня в конце есть следующие предупреждения:

18164:M 12 Mar 07:24:28.962 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.

18164:M 12 Mar 07:24:28.962 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add ‘vm.overcommit_memory = 1’ to /etc/sysctl.conf and then reboot or run the command ‘sysctl vm.overcommit_memory=1’ for this to take effect.

18164:M 12 Mar 07:24:28.962 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command ‘echo never > /sys/kernel/mm/transparent_hugepage/enabled’ as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.

Фикс для первого – выполняем в консоли:

sysctl -w net.core.somaxconn=512

и в конец /etc/rc.local вставляем эту же команду.

Фикс для второго – выполняем в консоли:

sysctl vm.overcommit_memory=1

и в конец файла  /etc/sysctl.conf добавляем строку:

vm.overcommit_memory = 1

Фикс для третьего:

sudo apt install hugepages 
sudo hugeadm --thp-never

И добавляем последнюю команду в конец /etc/rc.local (но перед exit 0).

#!/bin/sh -e 
# 
# rc.local 
# 
# This script is executed at the end of each multiuser runlevel. 
# Make sure that the script will "exit 0" on success or any other 
# value on error. 
# 
# In order to enable or disable this script just change the execution 
# bits. 
# 
# By default this script does nothing. 
sysctl -w net.core.somaxconn=512
hugeadm --thp-never 
exit 0

Так как изменений достаточно много – просто перезагрузим сервер и проверим лог Redis:

1556:M 12 Mar 08:30:13.214 # Server started, Redis version 3.0.6
1556:M 12 Mar 08:30:13.215 * DB loaded from disk: 0.001 seconds
1556:M 12 Mar 08:30:13.216 * The server is now ready to accept connections on port 6379

Всё Ок. Подключаем к nextCloud.

Есть два варианта – через сокеты или через порт. По умолчанию Redis слушает только на порту 6379 (видно из лога выше).

Через сокет. Для этого в /etc/redis/redis.conf раскомментируем и правим строчки:

unixsocket /var/run/redis/redis.sock 
unixsocketperm 777

и рестартуем Redis:

service redis restart

В логe Redis должны увидеть:

2712:M 12 Mar 08:51:53.891 # Server started, Redis version 3.0.6
2712:M 12 Mar 08:51:53.892 * DB loaded from disk: 0.001 seconds
2712:M 12 Mar 08:51:53.892 * The server is now ready to accept connections on port 6379
2712:M 12 Mar 08:51:53.892 * The server is now ready to accept connections at /var/run/redis/redis.sock

то есть сервер Redis слушает и сокет, и порт.

Теперь правим конфиг /var/www/nextcloud/config/config.php, добавляя параметры:

'memcache.local' => '\\OC\\Memcache\\Redis', 
'memcache.locking' => '\\OC\\Memcache\\Redis', 
'redis' => array ( 
  'host' => '/var/run/redis/redis.sock', 
  'port' => 0, 
  'timeout' => 0.0, 
  'password' => '', 
),

Это для сокетов.

Если же через порт, то –

'memcache.local' => '\\OC\\Memcache\\Redis', 
'memcache.locking' => '\\OC\\Memcache\\Redis', 
'redis' => array ( 
  'host' => 'localhost', 
  'port' => 6379, 
  'timeout' => 0.0, 
  'password' => '', 
),

К сожалению, без unixsocketperm 777 (или же unixsocketperm 770 + добавление www-data в группу redis) запустить связку nextCloud+Redis не удалось.

Поэтому у себя я обратно закомментировал строки

#unixsocket /var/run/redis/redis.sock 
#unixsocketperm 777

рестартовал Redis и в nextCloud указал конфиг через порт.

2.5. PHP OPcache

Тут просто – находим php.ini (у меня /etc/php/7.0/apache2/php.ini ) и в секции [opcache] просто вставляем (или раскомментируем-исправляем, кому как удобней):

opcache.enable=1 
opcache.enable_cli=1 
opcache.interned_strings_buffer=8 
opcache.max_accelerated_files=10000 
opcache.memory_consumption=128 
opcache.save_comments=1 
opcache.revalidate_freq=1

Ни и рестартуем аппач:

service apache2 restart

Если всё получилось, то теперь в Settings / Basic Settings увидим только одно предупреждение:

2.6. Включаем HTTPS+Let’s Encrypt

Проще всего идти по инструкции от DigitalOcean или от создателей CertBot:

add-apt-repository ppa:certbot/certbot 
apt update 
apt install python-certbot-apache 
certbot --apache -d cloud.example.com

Отвечаем на вопросы, в конце я также выбираю вариант:

2: Redirect – Make all requests redirect to secure HTTPS access.

В результате получены сертификаты, активирован HTTPS + HTTP перенаправлен на HTTPS (certbot создал свой собственный конфиг для HTTPS на базе имеюбщегося конфига HTTP).

Красота. Почти – смотрим Settings / Basic settings и видим предупреждение:

The “Strict-Transport-Security” HTTP header is not set to at least “15552000” seconds. For enhanced security, it is recommended to enable HSTS as described in the security tips.

Для фикса правим созданный CertBot файл /etc/apache2/sites-vailable/000-default-le-ssl.conf , добавив строки:

<IfModule mod_headers.c> 
Header always set Strict-Transport-Security "max-age=15552000; includeSubDomains" 
</IfModule>

Должно получиться так:

<IfModule mod_ssl.c>
 <VirtualHost *:443>
  ServerAdmin webmaster@localhost 
  DocumentRoot /var/www/nextcloud 
  <Directory /var/www/nextcloud/>
   Options +FollowSymlinks 
   AllowOverride All
   <IfModule mod_dav.c>
    Dav off 
   </IfModule> 
   <IfModule mod_headers.c> 
    Header always set Strict-Transport-Security "max-age=15552000; includeSubDomains" 
   </IfModule> 
   SetEnv HOME /var/www/nextcloud 
   SetEnv HTTP_HOME /var/www/nextcloud 
  </Directory> 
  ErrorLog ${APACHE_LOG_DIR}/error.log 
  CustomLog ${APACHE_LOG_DIR}/access.log combined 
  ServerName cloud.example.com 
  SSLCertificateFile /etc/letsencrypt/live/cloud.example.com/fullchain.pem 
  SSLCertificateKeyFile /etc/letsencrypt/live/cloud.cexample.com/privkey.pem 
  Include /etc/letsencrypt/options-ssl-apache.conf 
 </VirtualHost> 
</IfModule>

Проверяем конфиг на ошибки:

apache2ctl configtest

Если Syntax Ok – перезапускаем аппач:

service apache2 restart

Заходим на Settings / Basic settings – “All checks passed”. Ура:

Ну и у себя я переключил с AjAX на Cron.

2.7. Server-side encryption

Так как сервер в облаках, включаем шифрование данных на стороне сервера.

Для этого сперва активируем модуль (под иконкой профиля выбираем +Apps ), там идем в Disabled Apps и включаем модуль Default encryption module :

Затем идем в Settings / Encryption и включаем Enable server-side encryption, внимательно читаем текст красным и жмем Enable encryption:

Ну а дальше – проверим, что получилось.

3. Perfomance tests

Для проверки производительности проверял две ситуации – один большой фойл (~1G) и папка ~200М с примерно 200 файлами.

Что имеем:

Чтобы исключить влияние канала на тесты – проверяем канал Speedtest’ом на Нюрнберг:

4. Выводы

  1. Если цель “за 5-10 $ получить хранилище”, то поднимать свой сервер не имеет смысла – схожие по цене тарифы от облачных хранилищ дают гораздо больше места с гораздо большей скоростью доступа + хорошую интеграцию практически со всеми платформами.
  2. Если не устраивает, что “данные хранятся где-то там” (то есть вопросы безопасности), то есть варианты:
    • Boxcryptor или аналогичное решение, еще грубо € 4-8 за человека/месяц;
    • если же скорость доступа в 5-20М устраивает, то поднимаем свой сервер в облаках с server-side encryption + SSL (что и описано в этой статье);
    • если нужна скорость больше, можно попробовать взять план с большим объемом трафика. В теории больший объем трафика подразумевает большую полосу пропускания. Но, сюрприз!, в тестах Hetzner показал максимальную скорость в 20Мбит/с. Несложные расчеты показывают, что даже если постоянно скорость будет 20М, то за месяц объем трафика будет … ~5.8TB вместо обещанных 20ТB. А учитывая, что средняя скорость была примерно 5Мбит/сек, то и 5.8TB – это очень оптимистично. Возможно, в пределах датацентра или недалеко от него эти 20ТБ вполне реально выбрать, но в моем случае это оказался скорее маркетинговый ход, чем реальность. В то же время 2TB в плане DigitalOcean – звучат вполне реалистично и, возможно, переключившись на план с большим трафиком получим большую среднюю скорость;
    • берем выделенный (dedicated) сервер в датацентре и обеспечиваем ему необходимый канал;
    • collocation + необходимый канал;
    • сервер на территории компании. Мой вариант. Ибо необходима и достаточно большая скорость (5-20М слишком мало), и существуют вопросы безопасности (внутренняя документация компании. Хоть и не сильно секретная, но таки составляющая определенную коммерческую тайну). Поэтому чем наворачивать связку облачный файловый сервер + дополнительное шифрование проще поднять защищенный сервер внутри компании.

Резюмируя. Учитывая, что резервирование каналов + серверная уже имеются, я вернулся к истокам, но в чуть более современной реинкарнации – виртуальный сервер nextCloud (абсолютно аналогично описанному в статье), только в своей личной DMZ зоне + 2 канала 100М (резервирование/балансировка). Естественно, с регулярными автоматическими бэкапами.