Установка ownCloud 9 на CentOS 7 с Nginx
Содержание
Однажды я подумал о том, что хорошо бы сохранять заметки Org Mode (на случай непредвиденных ситуаций) где-нибудь помимо домашнего компьютера, да и фоточки с телефона бекапить. Для первой задачи использование Git было явным оверкиллом, а с учётом второй задачи в качестве очевидного решения напрашивалась синхронизация через облачный сервис. В качестве "облака" я выбрал ownCloud — многопользовательский self-hosted сервер для хранения, синхронизации и обмена данными с открытым исходным кодом.
Помимо своей основной функциональности ownCloud предлагает:
-
доступ через:
- веб-интерфейс;
- клиенты для синхронизации под основные платформы;
- протокол WebDAV.
- управление пользователями с настраиваемыми правами доступа, квотами и обменом данными (sharing) между пользователями.
-
приложения для расширения базовой функциональности:
- календарь;
- контакты;
- галерея;
- музыкальный проигрыватель;
- новостной агрегатор (Atom & RSS);
- текстовый редактор;
- … и другие.
-
возможность подключения внешних хранилищ:
- Dropbox;
- Amazon S3;
- ownCloud;
- Google Drive;
- FTP;
- … и другие.
- … и многое другое.
В данной статье описана установка ownCloud со следующей конфигурацией ПО:
- CentOS 7.2
- ownCloud 9.0
- PHP 5.6
- Nginx 1.6 (веб-сервер)
- MariaDB 5.5 (СУБД)
- Redis 2.8 (memory cache)
Установка ПО
Нам понадобятся пакеты из репозитория EPEL:
yum install -y epel-release
Установим основные зависимости ownCloud.
$ yum install -y \
mariadb \
mariadb-server \
nginx \
policycoreutils-python \
setroubleshoot \
libxml2 \
redis \
certbot
PHP
Для работы ownCloud и используемых им приложений нам понадобится PHP и некоторые библиотеки для этого языка. В CentOS несколько протухшая версия PHP, поэтому добавим репозитории Remi со свежими сборками:
$ wget http://rpms.famillecollet.com/enterprise/remi-release-7.rpm
$ rpm -Uvh remi-release-7.rpm
Включим нужные нам репозитории (мы будем использовать PHP версии 5.6):
[remi]
# [... skipped ...]
enabled=1 # поменяли enabled с 0 на 1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-remi
# [... skipped ...]
[remi-php56]
# [... skipped ...]
enabled=1 # поменяли enabled с 0 на 1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-remi
/etc/yum.repos.d/remi.repo
Теперь можно установить сами пакеты:
$ yum install -y \
php \
php-fpm \
php-cli \
php-mcrypt \
php-gd \
php-xml \
php-common \
php-ldap \
php-mbstring \
php-mysqlnd \
php-pdo \
php-pear \
php-process \
php-intl \
php-pecl-redis \
php-pecl-imagick
ownCloud
Следующий шаг — установка самого ownCloud. Мы будем использовать официальный ownCloud для CentOS. Импортируем ключ репозитория:
$ rpm --import https://download.owncloud.org/download/repositories/stable/CentOS_7/repodata/repomd.xml.key
Добавим репозиторий и установим пакет owncloud-files:
$ wget http://download.owncloud.org/download/repositories/stable/CentOS_7/ce:stable.repo \
-O /etc/yum.repos.d/ce:stable.repo
$ yum clean expire-cache
$ yum install owncloud-files -y
При установке из репозитория ownCloud можно воспользоваться двумя опциями:
- owncloud — установить файлы ownCloud со всеми обязательными зависимостями, предлагаемыми по умолчанию — это PHP, веб-сервер Apache и СУБД MySQL (MariaDB);
- owncloud-files — установить только файлы ownCloud; при этом установка зависимостей ложится на плечи пользователя.
Так как мы собираемся использовать Nginx вместо Apache, то мы остановились на втором варианте.
Предварительная настройка
firewalld
Чуть ли не самое первое, что необходимо сделать на свежем сервере — это включить и настроить файервол. Мы будем использовать вариант, предлагаемый по умолчанию в CentOS.
Запускаем firewalld:
$ systemctl start firewalld
$ systemctl enable firewalld
Определяем зону по умолчанию:
$ firewall-cmd --get-default-zone
public
Разрешаем доступ по http и https (порты 80 и 443, соответственно):
$ firewall-cmd --zone=public --add-service=http --permanent
success
$ firewall-cmd --zone=public --add-service=https --permanent
success
$ firewall-cmd --reload
ImageTragick
К моменту написания статьи ([2016-05-23 Mon]) широкую известность приобрело семейство эксплоитов, обнаруженных в наборе библиотек для обработки изображений ImageMagick, получившее ироничное название ImageTragick. Чтобы избавить себя от опасности, отредактируем файл политик в соответствии с рекомендациями:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE policymap [
<!ELEMENT policymap (policy)+>
<!ELEMENT policy (#PCDATA)>
<!ATTLIST policy domain (delegate|coder|filter|path|resource) #IMPLIED>
<!ATTLIST policy name CDATA #IMPLIED>
<!ATTLIST policy rights CDATA #IMPLIED>
<!ATTLIST policy pattern CDATA #IMPLIED>
<!ATTLIST policy value CDATA #IMPLIED>
]>
<policymap>
<policy domain="coder" rights="none" pattern="EPHEMERAL" />
<policy domain="coder" rights="none" pattern="HTTPS" />
<policy domain="coder" rights="none" pattern="HTTP" />
<policy domain="coder" rights="none" pattern="URL" />
<policy domain="coder" rights="none" pattern="FTP" />
<policy domain="coder" rights="none" pattern="MVG" />
<policy domain="coder" rights="none" pattern="MSL" />
<policy domain="coder" rights="none" pattern="TEXT" />
<policy domain="coder" rights="none" pattern="LABEL" />
<policy domain="path" rights="none" pattern="@*" />
</policymap>
/etc/ImageMagick/policy.xml
Права
Для корректной работы ownCloud нужно выставить корректные права и владельца директорий, которые он использует, и настроить для них контекст SELinux (отключать SELinux мы не будем — это малодушный, неспортивный шаг, который заставляет Dan Walsh плакать, ну и вредит безопасности). Кроме того, разрешим вебсерверу создавать TCP-соединения и отправлять почту.
Для этого воспользуемся модифицированным вариантом скрипта, предложенным в документации к ownCloud:
ocpath='/var/www/html/owncloud'
htuser='nginx'
htgroup='nginx'
rootuser='root'
# PHP Session path (on CentOS)
session_path='/var/lib/php/session'
printf "Creating possible missing Directories\n"
mkdir -p $ocpath/data
mkdir -p $ocpath/assets
mkdir -p $ocpath/updater
printf "chmod Files and Directories\n"
find ${ocpath}/ -type f -print0 | xargs -0 chmod 0640
find ${ocpath}/ -type d -print0 | xargs -0 chmod 0750
printf "chown Directories\n"
chown -R ${rootuser}:${htgroup} ${ocpath}/
chown -R ${htuser}:${htgroup} ${ocpath}/apps/
chown -R ${htuser}:${htgroup} ${ocpath}/assets/
chown -R ${htuser}:${htgroup} ${ocpath}/config/
chown -R ${htuser}:${htgroup} ${ocpath}/data/
chown -R ${htuser}:${htgroup} ${ocpath}/themes/
chown -R ${htuser}:${htgroup} ${ocpath}/updater/
chmod +x ${ocpath}/occ
printf "chmod/chown .htaccess\n"
if [ -f ${ocpath}/.htaccess ]
then
chmod 0644 ${ocpath}/.htaccess
chown ${rootuser}:${htgroup} ${ocpath}/.htaccess
fi
if [ -f ${ocpath}/data/.htaccess ]
then
chmod 0644 ${ocpath}/data/.htaccess
chown ${rootuser}:${htgroup} ${ocpath}/data/.htaccess
fi
# Owned by root:apache (by default), need to change this
# to allow the webserver process to access session data
printf "chown PHP session path"
chown -R ${htuser}:${htgroup} ${session_path}
printf "Configuring SELinux\n"
semanage fcontext -a -t httpd_sys_rw_content_t "${ocpath}/data"
restorecon "${ocpath}/data"
semanage fcontext -a -t httpd_sys_rw_content_t "${ocpath}/config"
restorecon "${ocpath}/config"
semanage fcontext -a -t httpd_sys_rw_content_t "${ocpath}/apps"
restorecon "${ocpath}/apps"
# Allow the webserver to create TCP connections
setsebool -P httpd_can_network_connect on
# Allow the webserver to send emails
setsebool -P httpd_can_sendmail on
Nginx
Запустим вебсервер:
$ systemctl start nginx
$ systemctl enable nginx
SSL
Детали получения сертификатов с помощью LetsEncrypt рассмотрены в другой статье, здесь мы кратко опишем выполняемые действия.
Создадим директорию для плагина Webroot:
$ install -o nginx -g nginx -d /var/www/common/letsencrypt
Для того, чтобы обезопасить себя от некоторых атак, направленных против приложений, использующих протоколы HTTPS и TLS (читай, против вебсервера), необходимо сгенерировать безопасные параметры для используемого этими протоколами криптографического алгоритма Diffie-Hellman.
$ openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048
В результате получим файл dhparam.pem
с искомыми параметрами, путь которому мы укажем в конфигурации
сервера Nginx.
Удалим дефолтный сервер из /etc/nginx/nginx.conf
, добавим блок для прохождения acme challenge, который
будет перенаправлять остальные запросы на https:
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
events {
worker_connections 1024;
}
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
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:k\
EDH+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-ECDS\
A-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;
server {
listen 80 default_server;
server_name _;
location /.well-known/acme-challenge/ {
default_type "text/plain";
root /var/www/common/letsencrypt;
}
location / {
return 301 https://$host$request_uri;
}
}
include /etc/nginx/conf.d/*.conf;
}
/etc/nginx/nginx.conf
Также мы добавили некоторые опции SSL, включая:
- разрешённые протоколы SSL (
ssl_protocols
), - сгенерированние ранее параметры Diffie-Hellman (
ssl_dhparam
), - whitelist безопасных и blacklist небезопасных серверных шифров (
ssl_ciphers
) - параметры сессии и др.;
Перезагрузим конфигурацию вебсервера:
$ systemctl reload nginx
Создадим скрипт для генерации сертификатов (скрипт принимает в качестве параметра доменное имя, для которого нужно сгенерировать сертификат):
#!/bin/bash
set -e
WEBROOT=/var/www/common/letsencrypt
# Obtain/renew certificate
/usr/bin/env certbot certonly --webroot --webroot-path=${WEBROOT} \
--domains "$1" --agree-tos \
--rsa-key-size 4096 \
--force-renewal \
--email s.b.maximov@gmail.com
# Reload webserver
systemctl reload nginx
/etc/letsencrypt/cert.sh
Далее напишем systemd-юнит, который будет запускать непосредственную генерацию сертификата:
[Unit]
Description=Install/Renew SSL certificates for %I
[Service]
Type=oneshot
ExecStart=/etc/letsencrypt/cert.sh %I
/etc/systemd/system/cert@.service
Это так называемый template-юнит. Он отличает от обычного тем, что
при запуске (инстацировании) ему передаётся параметр (в нашем случае домен),
который доступен внутри юнита в виде параметра %I
. Например, при инстацировании
шаблонного юнита с помощью команды
$ systemctl start cert@cloud.maximov.space.service
параметром является часть названия юнита от символа @
до суффикса .service
. В
инстацированном юните все вхождения %I
будут заменены на cloud.maximov.space
.
Для периодического обновления сертификатов также напишем шаблонный таймер, при инстацировании которого будет запускаться соответствующий сервис:
[Unit]
Description=Run cert@%I.service every month
[Timer]
OnCalendar=monthly
Persistent=true
[Install]
WantedBy=timers.target
/etc/systemd/system/cert@.timer
Запустим юнит и таймер:
systemctl start cert@cloud.maximov.space.service
systemctl start cert@cloud.maximov.space.timer
systemctl enable cert@cloud.maximov.space.timer
В результате получим сертификат, лежащий в директории /etc/letsencrypt/live/cloud.maximov.space/
.
PHP-FPM
PHP-FPM — это популярная реализация протокола FastCGI для PHP, созданная с упором на производительность.
Нам нужно, чтобы php-fmp запускался от пользователя nginx. Также необходимо задать переменные окружения, которые будут доступны процессу php-fpm (по умолчанию процесс запускается в пустом окружении). Для этого внесём следующие изменения в файл конфигурации php-fpm (остальные настройки трогать не будем).
user = nginx
group = nginx
env[HOSTNAME] = $HOSTNAME
env[PATH] = /usr/local/sbin:/sbin:/bin:/usr/sbin:/usr/bin:
env[TMP] = /tmp
env[TMPDIR] = /tmp
env[TEMP] = /tmp
/etc/php-fpm.d/www.conf
Запускаем php-fpm:
$ systemctl start php-fpm
$ systemctl enable php-fpm
Конфигурация Nginx для ownCloud
За основу возьмём конфигурацию Nginx, предлагаемую Owncloud (wiki), внеся следующие изменения:
--- owncloud.conf.sample 2016-05-20 09:29:06.232034660 -0400
+++ cloud.maximov.space.conf 2016-05-23 05:09:57.105163202 -0400
@@ -1,25 +1,17 @@
upstream php-handler {
server 127.0.0.1:9000;
- #server unix:/var/run/php5-fpm.sock;
-}
-
-server {
- listen 80;
- server_name cloud.example.com;
- # enforce https
- return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl;
- server_name cloud.example.com;
+ server_name cloud.maximov.space;
- ssl_certificate /etc/ssl/nginx/cloud.example.com.crt;
- ssl_certificate_key /etc/ssl/nginx/cloud.example.com.key;
+ ssl_certificate /etc/letsencrypt/live/cloud.maximov.space/fullchain.pem;
+ ssl_certificate_key /etc/letsencrypt/live/cloud.maximov.space/privkey.pem;
# Add headers to serve security related headers
# Before enabling Strict-Transport-Security headers please read into this topic first.
- #add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;";
+ add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;";
add_header X-Content-Type-Options nosniff;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
@@ -28,7 +20,7 @@
add_header X-Permitted-Cross-Domain-Policies none;
# Path to the root of your installation
- root /var/www/owncloud/;
+ root /var/www/html/owncloud/;
location = /robots.txt {
allow all;
@@ -95,7 +87,7 @@
add_header Cache-Control "public, max-age=7200";
# Add headers to serve security related headers (It is intended to have those duplicated to the ones above)
# Before enabling Strict-Transport-Security headers please read into this topic first.
- #add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;";
+ add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;";
add_header X-Content-Type-Options nosniff;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
Мы изменили:
- имя сервера (
cloud.maximov.space
), - корень сайта (
/var/www/html/owncloud
), - пути к файлам сертификата (
/etc/letsencrypt/live/cloud.maximov.space/*
), - добавили заголовок
Strict-Transport-Security
.
Полный конфиг:
upstream php-handler {
server 127.0.0.1:9000;
}
server {
listen 443 ssl;
server_name cloud.maximov.space;
ssl_certificate /etc/letsencrypt/live/cloud.maximov.space/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/cloud.maximov.space/privkey.pem;
# Add headers to serve security related headers
# Before enabling Strict-Transport-Security headers please read into this topic first.
add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;";
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;
# Path to the root of your installation
root /var/www/html/owncloud/;
location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}
# The following 2 rules are only needed for the user_webfinger app.
# Uncomment it if you're planning to use this app.
#rewrite ^/.well-known/host-meta /public.php?service=host-meta last;
#rewrite ^/.well-known/host-meta.json /public.php?service=host-meta-json last;
location = /.well-known/carddav { return 301 $scheme://$host/remote.php/dav; }
location = /.well-known/caldav { return 301 $scheme://$host/remote.php/dav; }
location /.well-known/acme-challenge { }
# set max upload size
client_max_body_size 512M;
fastcgi_buffers 64 4K;
# Disable gzip to avoid the removal of the ETag header
gzip off;
# Uncomment if your server is build with the ngx_pagespeed module
# This module is currently not supported.
#pagespeed off;
error_page 403 /core/templates/403.php;
error_page 404 /core/templates/404.php;
location / {
rewrite ^ /index.php$uri;
}
location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)/ {
deny all;
}
location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console) {
deny all;
}
location ~ ^/(?:index|remote|public|cron|core/ajax/update|status|ocs/v[12]|updater/.+|ocs-provider/.+|core/templates/40[34])\.php(?:$|/) {
include fastcgi_params;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
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_param front_controller_active true;
fastcgi_pass php-handler;
fastcgi_intercept_errors on;
}
location ~ ^/(?:updater|ocs-provider)(?:$|/) {
try_files $uri/ =404;
index index.php;
}
# Adding the cache control header for js and css files
# Make sure it is BELOW the PHP block
location ~* \.(?:css|js)$ {
try_files $uri /index.php$uri$is_args$args;
add_header Cache-Control "public, max-age=7200";
# Add headers to serve security related headers (It is intended to have those duplicated to the ones above)
# Before enabling Strict-Transport-Security headers please read into this topic first.
add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;";
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;
# Optional: Don't log access to assets
access_log off;
}
location ~* \.(?:svg|gif|png|html|ttf|woff|ico|jpg|jpeg)$ {
try_files $uri /index.php$uri$is_args$args;
# Optional: Don't log access to other assets
access_log off;
}
}
/etc/nginx/conf.d/cloud.maximov.space.conf
Перезагружаем конфигурацию Nginx:
$ systemctl reload nginx
Mariadb
MariaDB — это совместимый с оригиналом форк СУБД MySQL, рождённый как ответ на невнятную политику владельца MySQL — печально известную корпорацию Oracle. В последнее время форк приобрёл (заслуженно) большую популярность, чем оригинал, что привело к тому, что многие проекты перешли с MySQL на MariaDB, и в большинстве дистрибутивов Linux MariaDB используется по умолчанию вместо MySQL.
Запустим сервер MariaDB.
$ systemctl start mariadb
$ systemctl enable mariadb
Завершим установку Mariadb — установим root-пароль, зададим полезные настройки, связанные с безопасностью:
$ mysql_secure_installation
Redis
Redis — это in-memory-хранилище, используемое как БД, кэш и очередь сообщений. Redis рекомендуемется в документации к ownCloud для использования в качестве memory cache.
Воспользуемся советом из официальной документации Redis и установим
параметр vm.overcommit_memory
:
$ echo 'vm.overcommit_memory=1' > /etc/sysctl.conf
$ sysctl vm.overcommit_memory=1
Запускаем Redis и проверяем, что Nginx может к нему коннектиться:
$ systemctl start redis
$ systemctl enable redis
$ sudo -u nginx redis-cli
Завершение установки Owncloud
Запустим скрипт, который создаст структуру базы данных для ownCloud:
cd /var/www/html/owncloud
sudo -u nginx php occ maintenance:install \
--database mysql --database-name owncloud \
--database-user root --database-pass DB_ROOT_PASS \
--admin-user admin --admin-pass ADMIN_PASS
Установка завершена! Теперь уже можно использовать ownCloud, но для оптимальной работы мы подкорректируем настройки ownCloud вручную:
Конфигурация ownCloud
Добавим cloud.maximov.space
к доверенным доменам (IP-адреса и домены,
которым разрешено подключаться к ownCloud):
'trusted_domains' => array (
'cloud.maximov.space',
),
/var/www/html/owncloud/config/config.php
Настроем подключение к Redis в конфиге Owncloud для использования в качестве memory cache:
'memcache.local' => '\OC\Memcache\Redis',
'memcache.locking' => '\OC\Memcache\Redis',
'redis' => array (
'host' => 'localhost',
'port' => 6379,
),
/var/www/html/owncloud/config/config.php
Настроим периодический запуск maintenance-задач для ownCloud:
$ crontab -u nginx -e
*/15 * * * * php -f /var/www/html/owncloud/cron.php
Заменить настройку overwrite.cli.url
на следующее значение (это нужно в том
числе для того, чтобы в письмах генерировался корректный адрес сервера ownCloud):
'overwrite.cli.url' => 'https://cloud.maximov.space',
Установим язык по умолчанию:
'default_language' => 'ru',