Nextcloud на базе NGINX с SSL

Материал из Записки на полях
Перейти к навигации Перейти к поиску

Развертываем LEMP

Начинать, пожалуй, стоит с установки наиболее привычных утилит для работы: htop, iotop, iftop, mc. Затем приступаем к самому LEMP — Linux, Nginx (его произносят как Engine X), MySQL/MariaDB и PHP. Linux у нас уже есть. Почему Ubuntu 16.04, а не, скажем, Debian или CentOS? Я не люблю rpm, и с Ubuntu проще в плане репозиториев со свежими версиями софта. Очень не люблю практику «make install» на боевых серверах. Все же более оптимальным является путь использования пакетного менеджера. Этого принципа и будем придерживаться.

Ставим софт

Добавляем репозиторий с более свежими версиями nginx. Там были закрыты некоторые баги и уязвимости. Копируем GPG ключ разработчиков Nginx и создаем новый источник-репозиторий для apt:

curl http://nginx.org/keys/nginx_signing.key | apt-key add

В файл добавляем ссылки на репозиторий для Ubuntu 16.04 Xenial:

echo 'deb http://nginx.org/packages/mainline/ubuntu/ xenial nginx' >> /etc/apt/sources.list.d/nginx.list
echo 'deb-src http://nginx.org/packages/mainline/ubuntu/ xenial nginx' >> /etc/apt/sources.list.d/nginx.list

Устанавливаем все требуемы пакеты :

apt-get update
apt-get install nginx mariadb-server mariadb-client 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 php7.0-ldap

Выполняем настройку

Настроим MariaDB

Выполняем hardening-процедуру, отключая тестовые базы и прочие потенциальные дыры в защите:

mysql_secure_installation

Будет запущен диалог, в котором надо будет ответить на серию вопросов. В этом же диалоге мы задаем пароль для root. Он потребуется позже, когда будем создавать базу для nextcloud.

Так как инсталляция у нас маленькая, то в тонкости оптимизации мы вдаваться не будем. Поэтому разворачиваем с более или менее дефолтным конфигом. Username и password подставьте те, которые будет использовать owncloud для доступа к своей базе данных.

mysql -uroot -p

create database nextclouddb CHARACTER SET utf8 COLLATE utf8_general_ci;
grant all privileges on nextclouddb.* to 'Username'@'localhost' identified by 'password';
flush privileges;
exit;

Настроим php7.0-fpm

Для работы Nextcloud требуется отредактировать переменные окружения:

vi /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

#В том же файле для корректной работы php-fpm правим пользователя от которого он работает

listen.owner = nginx
listen.group = nginx
listen.mode = 0660


Установка nextcloud

cd /tmp
wget https://download.nextcloud.com/server/releases/nextcloud-10.0.1.tar.bz2
tar -xvf nextcloud-10.0.1.tar.bz2 -C /usr/share/nginx/html/
rm nextcloud-10.0.1.tar.bz2

Подправим права на папку

chown www-data:www-data -R /usr/share/nginx/html/nextcloud/

Настраиваем Let's Encrypt и конфигурируем Nginx

Основная идея 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
wget https://dl.eff.org/certbot-auto
chmod a+x /usr/local/sbin/certbot-auto

Для первоначального запроса сертификатов необходим сайт, через который будет осуществляться подтверждение. Для этих целей используем сайт Default из штатной установки Nginx. В конце настройки его можно будет удалить - подтверждение будет идти через сайт Nextcloud.

Редактируем конфиг nginx и разрешаем доступ к тому каталогу, в который будет писать webroot вариант certbot'а:

vi /etc/nginx/config.d/default

Добавляем строки:

location ~ /.well-known {
                root   /usr/share/nginx/html;
                allow all;
}

Проверяем, что всё правильно:

nginx -t

Перезапускаем сервис nginx:

service nginx restart

Теперь можно запустить certbot и сгенерировать сертификаты для нашего домена.

certbot-auto certonly -a webroot --webroot-path=/usr/share/nginx/html -d cloud.mysite.net

При первом запуске certbot-auto будет устанавливать небходимые для его работы пакеты. В диалоговом окне нужно будет ввести адрес электронной почты и согласиться с условиями использования

Certbot складывает актуальные версии сертификатов в каталог /etc/letsencrypt/live/, создавая симлинки. Внутри будут лежать файлы:

cert.pem: сертификат вашего домена
chain.pem: chain сертификат Let's Encrypt
fullchain.pem: комбинированный сертификат из cert.pem и chain.pem
privkey.pem: приватный ключ вашего сертификата

Генерируем ключ Диффи — Хеллмана:

openssl dhparam -out /etc/ssl/certs/dhparam.pem 4096

Настройка Nginx

Отлично. Теперь, прописав в конфиге Nginx ссылку на /etc/letsencrypt/live/, мы будем иметь всегда актуальную версию. Создаем новый конфиг для нашего домена:

vi /etc/nginx/conf.d/example.mysite.ru.conf
upstream php-handler {
  #server 127.0.0.1:9000;
  server unix:/run/php/php7.0-fpm.sock;
 }

server {
    listen 80;
    server_name cloud.mysite.ru;
    # Редирект на HTTPS версию сайта.
    return 301 https://$server_name$request_uri;
}
server {
    # Поддержка HTTPS
    listen 443 ssl;
    server_name cloud.mysite.ru;

    # Задаем главную страницу
    index index.php index.html index.htm index.nginx-debian.html;

    # Включаем логгирование
    error_log /var/log/nginx/cloud.error.log;
    access_log /var/log/nginx/cloud.access.log;

    ### SSL CONFIGURATION ###
    ssl on;
    ssl_certificate /etc/letsencrypt/live/cloud.mysite.ru/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/cloud.mysite.ru/privkey.pem;
    ssl_trusted_certificate /etc/letsencrypt/live/cloud.mysite.ru/fullchain.pem;
    ssl_dhparam /etc/ssl/certs/dhparam.pem;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;
    ssl_ciphers "EECDH+AESGCM:EECDH+CHACHA20:EECDH+AES256:!AES128";
    ssl_stapling on;
    ssl_stapling_verify on;

    resolver 8.8.8.8 8.8.4.4;

    ### КОНЕЦ КОНФИГУРАЦИИ SSL ###
    # Дополнительные заголовки для увеличения безопасности, в частности, первая строчка добавляет поддержку HSTS

    add_header Strict-Transport-Security 'max-age=631138519; includeSubDomains; preload' always;
    add_header Content-Security-Policy   "default-src 'self'; script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' blob data:";
    add_header X-Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' blob data:";
    add_header X-WebKit-CSP              "default-src 'self'; script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' blob data:";
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Xss-Protection "1; mode=block" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-Proxy-Cache "EXPIRED" always;

    # Дополнительные заголовки от разработчиков Nextcloud
    add_header X-Robots-Tag "none" always;
    add_header X-Download-Options "noopen" always;
    add_header X-Permitted-Cross-Domain-Policies "none" always;

    # Корневая директория сайта
    root /usr/share/nginx/html/nextcloud;

    # Максимальный размер файла, который мы сможем загрузить и увеличенный буфер
    client_max_body_size 3G;
    fastcgi_buffers 64 4K;

    # C gzip бывают проблемы в случае с Nextcloud, поэтому разработчики рекомендуют его отключить
    gzip off;

    # Кастомные страницы ошибок 403 и 404.
    error_page 403 /core/templates/403.php;
    error_page 404 /core/templates/404.php;

    ### Далее мы принудительно разрешаем/запрещаем чтение определенных директорий и файлов ###
    ### Помимо этого мы устанавливаем редиректы для красивых URL                           ###
    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 {
        root /usr/share/nginx/html/nextcloud;
        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;
    }
}

Создаём файлы логов нашего сайта:

touch /var/log/nginx/site.error.log
touch /var/log/nginx/site.access.log
chown nginx:nginx /var/log/nginx/site.access.log
chown nginx:nginx /var/log/nginx/site.error.log

Проверяем правильность конфига

nginx -t

И перезапускаем сервис

service nginx restart

Проверяем работу сайта - с адреса http://cloud.mysite.ru должен перебрасывать на https://cloud.mysite.ru

Автоматизируем обновление сертификата

Проверяем обновление сертификата с ключом --dry-run, который имитирует обновление, но ничего не меняет в реальности:

certbot-auto renew --dry-run

При запуске этой команды certbot свяжется с серверами EFF и попытается обновить свою версию, если это возможно, а затем и сертификаты. Причем не только на все доступные домены. Очень удобно. Если срок смены сертификата не подошел, то ничего не произойдет, и скрипт об этом сообщит.

Теперь можно добавить регулярный запуск скрипта crontab:

crontab -e

Внутрь добавляем регулярную задачу по обновлению сертификатов и их перезаливке в nginx d 2-30 ночи каждого понедельника:

30 2 * * 1 /usr/local/sbin/certbot renew --preferred-challenges http --nginx >> /var/log/le-renew.log
35 2 * * 1 /etc/init.d/nginx reload

certbot-auto проверяет требуется ли обновление сертификата. Если требуется обновление, то запрашивает новый.

Настраиваем службу кэширования

Важный момент. Без memory caching nexcloud может работать ощутимо задумчивее. Причем он непременно напомнит вам об этом на странице администратора. Выбор способа кэширования зависит от архитектуры системы. С рекомендациями от разработчиков вы можете ознакомиться тут. Если коротко, то для личного использования и небольших инсталляций рекомендуется использовать только APCu. Для малых организаций, при установке на один сервер — APCu для локального кэширования и Redis для file locking. Для установки на кластер в большой организации: Redis для всего, кроме локального кэширования.

Разработчики считают APCu наиболее быстрым вариантом для локального кэша. Если хватает оперативной памяти, то лучше использовать APCu для локального кэширования и Redis для file locking. Если памяти недостаточно, то рекомендуется использовать Redis и для того и другого.

В нашем варианте мы будем использовать только APCu. Установим соответствующий модуль для php:

apt-get install php-apcu

Теперь будет достаточно просто добавить их в конфигурационный файл nexcloud — config.php:

vi /usr/share/nginx/html/nextcloud/config/config.php
'memcache.local' => '\OC\Memcache\APCu',

Ссылки по теме

Поднимаем Owncloud с нуля с динамическим IP и Let's Encrypt.

Настройка Nextcloud на базе NGINX