Личное облако NextCloud на Raspberry Pi с nginx + php-fpm


  • 0

    NextCloud это Open Source решение для создания своего, “карманного” облака, последователь широкоизвестного OwnCloud, в свою очередь клона коммерческой платформы Dropbox.
    Основное отчилие NextCloud от OwnCloud - все что было платным в OwnCloud (прим. Android клиент) - теперь полностью бесплатно. Скачать клиенты можно на официальном сайте проекта nextcloud.com.
    Я установил все это добро на Raspberry Pi 3 Model B с 8GB картой памяти и USB флешкой Kingston DataTraveler G3 32GB в качестве постоянного носителя информации, в будущем планирую приобрести PiDrive на 1TB и перенести данные туда.

    Чем эта статья отличается от остальных?

    • Установка основывется на nginx + php-fpm
    • PHP версии 7
    • redis как кешировщик и база для хранения блокировок файлов, что сильно увеличивает производительность.
    • Логи отключены там где это можно, остальное перенесено в RAM, для уменшения износа microSD.
    • Временная папка используемая при загрузке файлов так же в RAM.
    • SSL от letsencrypt
    • Конфигурация заточена под загрузку больших файлов (4+ GB). И дело не в том, что загрузка мелкий файлов теперь “на дне”, а в том, что при базовой конфигурации максимальный размер файла не может превышать 512MB. Итак, поехали!

    Так как мы будем выполнять много команд требующих прав root, что-бы не мучатся с sudo - давайте сразу переключимся в root любым удобным способом. Например sudo -i
    Не забывайте повторить после перезагрузки.

    Настройка домена и проброса портов

    Проброс портов

    Так как статья о Raspberry Pi, а еще и с оговоркой “Личное облако” - предполагаю что Ваша Raspberry Pi, собственно как и моя имеет “серый” IP адрес за домашним роутером. Потому перед началом настройки внесите соответствующие настройки на Вашем роутере, нужно пробросить 80 и 443 порты с внешнего IP на внутренний IP Raspberry Pi. В моем случае это выглядит так.

    0_1473631066539_picloud1-0.png

    Домен

    Я для этих целей зарегистрировал специальный домен на dot.tk - picloud.ga, вы можете сделать так же или выделить для этих целей поддомен одного из доступных Вам доменов. Главное - A запись указывающая на Ваш внешний IP.

    0_1473631302590_picloud1-1.png


    Установка NextCloud на Raspberry Pi

    Создаем пользователя

    [email protected]:~ adduser --home /home/picloud.ga --shell /dev/null --disabled-password --disabled-login --gecos '' picloud
    

    Внешнее хранилище (опционально)

    Если Вы не собираетесь подключать внешнее хранилище - сразу переходите к следующему шагу “Скачиваем и распаковываем NextCloud”

    Я сразу определился для себя, что данные я буду хранить на внешнем диске. Это может быть USB флешка, может быть PiDrive или обычный внешний HDD, что угодно, но microSD карточки как по мне не самый надежный вариант для хранения своих фоточек из отпуска. Данный раздел опционален и если Вы не планируете использовать внешнее хранилище - переходите сразу к следующему шагу.
    Ничего особенного. Подключение внешнего диска подробно описано здесь. После подключения USB флешки смотрим fdisk -l, скорее всего флешка у нас определилась как /dev/sda, удаляем все разделы, создаем один и форматируем в ext4 (любителям xfs/brtfs можно использовать и их).

    [email protected]:~# fdisk -l
    
    Disk /dev/sda: 232.9 GiB, 250059350016 bytes, 488397168 sectors
    Units: sectors of 1 * 512 = 512 bytes
    Sector size (logical/physical): 512 bytes / 512 bytes
    I/O size (minimum/optimal): 512 bytes / 512 bytes
    Disklabel type: dos
    Disk identifier: 0xc618090a
    
    Device     Boot Start       End   Sectors   Size Id Type
    /dev/sda1          63 488397167 488397105 232.9G  c W95 FAT32 (LBA)
    
    Disk /dev/mmcblk0: 7.4 GiB, 7948206080 bytes, 15523840 sectors
    Units: sectors of 1 * 512 = 512 bytes
    Sector size (logical/physical): 512 bytes / 512 bytes
    I/O size (minimum/optimal): 512 bytes / 512 bytes
    Disklabel type: dos
    Disk identifier: 0x0ccea0b3
    
    Device         Boot Start      End  Sectors  Size Id Type
    /dev/mmcblk0p1       2048    43007    40960   20M 83 Linux
    /dev/mmcblk0p2      43008 15523839 15480832  7.4G 83 Linux
    
    ####### Посмотрели, пора и делать что-то. Удаляем существующий раздел и создаем новый во весь размер диска #######
    
    [email protected]:~# fdisk /dev/sda
    
    Welcome to fdisk (util-linux 2.25.2).
    Changes will remain in memory only, until you decide to write them.
    Be careful before using the write command.
    
    
    Command (m for help): d
    Selected partition 1
    Partition 1 has been deleted.
    
    Command (m for help): n
    Partition type
       p   primary (0 primary, 0 extended, 4 free)
       e   extended (container for logical partitions)
    Select (default p): p
    Partition number (1-4, default 1): 1
    First sector (2048-488397167, default 2048): 2048
    Last sector, +sectors or +size{K,M,G,T,P} (2048-488397167, default 488397167): 488397167
    
    Created a new partition 1 of type 'Linux' and of size 232.9 GiB.
    
    Command (m for help): w
    The partition table has been altered.
    Calling ioctl() to re-read partition table.
    Syncing disks.
    
    ####### Раздел создан, теперь нужно отформатировать #######
    
    [email protected]:~# mkfs.ext4 /dev/sda1
    mke2fs 1.42.12 (29-Aug-2014)
    Creating filesystem with 61049390 4k blocks and 15269888 inodes
    Filesystem UUID: 9ac7c40d-323a-424e-89d3-8718c224ed78
    Superblock backups stored on blocks: 
    	32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208, 
    	4096000, 7962624, 11239424, 20480000, 23887872
    
    Allocating group tables: done                            
    Writing inode tables: done                            
    Creating journal (32768 blocks): done
    Writing superblocks and filesystem accounting information: done   
    

    Создали раздел. Теперь его нужно примонтировать. Я буду хранить данные в /home/picloud.ga. Пропишем сразу в /etc/fstab

    /dev/sda1    /home/picloud.ga    ext4    defaults,nofail,errors=remount-ro    0    1
    

    Сейчас самое время перезагрузить систему, так как монтирование диска произойдет при перезагрузке. Если этого не сделать - все что Вы будете делать в следующем шаге - останется на microSD карте.

    Скачиваем и распаковываем NextCloud

    [email protected]:~ cd /home/picloud.ga
    [email protected]:~ wget https://download.nextcloud.com/server/releases/nextcloud-11.0.1.zip
    [email protected]:~ unzip *.zip && mv nextcloud/* . && rm -rf nextcloud*
    [email protected]spberrypi:~ chown -R picloud: /home/picloud.ga/*
    

    Установка необходимых пакетов

    Так как мы будем использовать php7, которого пока нет в основном репозитории - нужно добавить в /etc/apt/sources.list stretch репозиторий Raspbian и обновить пакетную базу в системе, это можно сделать такой, удобной конструкцией.

    cat <<EOF >> /etc/apt/sources.list
    deb http://mirrordirector.raspbian.org/raspbian/ stretch main contrib non-free rpi
    EOF
    apt-get update
    

    А теперь, непосредственно установка.

    sudo apt-get install -t stretch ntp ntpdate nginx php-fpm php-cli php-json php-curl php-imap php-gd php-xml php-zip php-intl php-mcrypt php-imagick php-mbstring php-smbclient php-smbclient redis-server php-redis php-sqlite3 php-mysql mariadb-server letsencrypt
    

    Во время установки у Вас будет запрошен пароль для дефолтного пользователя mysql. Не забудте его, он еще пригодится ;)

    Настройка nginx и php-fpm

    Конфигурационный файл для php-fpm /etc/php/7.0/fpm/pool.d/picloud.conf

    [picloud.ga]
    listen = /var/run/picloud.sock
    user = picloud
    group = picloud
    
    listen.owner = picloud
    listen.group = picloud
    listen.mode = 0666
    
    pm = dynamic
    pm.max_children = 50
    pm.start_servers = 3
    pm.min_spare_servers = 2
    pm.max_spare_servers = 10
    
    env[HOSTNAME] = $HOSTNAME
    env[PATH] = /usr/local/bin:/usr/bin:/bin
    env[TMP] = /tmp
    env[TMPDIR] = /tmp
    env[TEMP] = /tmp
    
    php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f [email protected]
    php_flag[display_errors] = off
    php_admin_value[memory_limit] = 256M
    php_admin_value[post_max_size] = 8G
    php_admin_value[max_execution_time] = 7200
    php_admin_value[max_input_time] = 7200
    php_admin_value[output_buffering] = 0
    php_admin_value[allow_url_fopen] = Off
    php_admin_value[upload_max_filesize] = 8G   
    php_admin_value[date.timezone] = Europe/Kiev
    php_admin_value[error_log] = /var/log/php7.0-fpm.log
    

    Конфигурационный файл для nginx /etc/nginx/conf.d/picloud.conf

    server {
        listen 80;
        listen 443 ssl http2;
        server_name picloud.ga;
        root /home/picloud.ga;
        index index.php;
    
        ssl on;
        ssl_certificate     /etc/letsencrypt/live/picloud.ga/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/picloud.ga/privkey.pem;
        ssl_session_timeout 7200s;
        ssl_ciphers               'AES128+EECDH:AES128+EDH:!aNULL';
        ssl_protocols              TLSv1 TLSv1.1 TLSv1.2;
        ssl_prefer_server_ciphers on;
    
        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;
    
        access_log  /var/log/nginx/picloud.access.log;
        error_log   /var/log/nginx/picloud.error.log;
    
        proxy_connect_timeout       7200;
        proxy_send_timeout          7200;
        proxy_read_timeout          7200;
        send_timeout                7200;
    
        location = /robots.txt {
            allow all;
            log_not_found off;
            access_log off;
        }
    
        location ^~ /.well-known/acme-challenge { allow all; }
    
        location = /.well-known/carddav { 
            return 301 $scheme://$host/remote.php/dav; 
        }
        location = /.well-known/caldav { 
            return 301 $scheme://$host/remote.php/dav; 
        }
    
        client_max_body_size 8G;
        fastcgi_buffers 64 4K;
        gzip 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;
            #Avoid sending the security headers twice
            fastcgi_param modHeadersAvailable true;
            fastcgi_param front_controller_active true;
            fastcgi_pass unix:/var/run/picloud.sock;
            fastcgi_intercept_errors on;
            fastcgi_request_buffering off;
    	fastcgi_read_timeout 7200;
        }
    
        location ~ ^/(?:updater|ocs-provider)(?:$|/) {
            try_files $uri/ =404;
            index index.php;
        }
    
        location ~* \.(?:css|js)$ {
            try_files $uri /index.php$uri$is_args$args;
            add_header Cache-Control "public, max-age=7200";
            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;
            access_log off;
        }
    
        location ~ /\.ht {
            deny all;
        }
    
    }
    

    Если сейчас попытатся перезапустить nginx - он не перезапустится, так как отсутствуют SSL сертификат и приватный ключ для Вашего домена. Создадим их.

    SSL от Let’s Encrypt

    Для получения сертификата уже должны быть активны пробросы портов на роутере и доменное имя указывающее на Ваш внешний IP. Выполняем следующую команду и сертификат с ключем окажется в директории /etc/letsencrypt/live/<ваш_домен>/

    [email protected]:~# letsencrypt certonly -d picloud.ga --email [email protected] --standalone --renew-by-default --agree-tos --standalone-supported-challenges tls-sni-01
    

    Так же, для автоматического обновления сертификата без остановки основного процесса nginx - добавте в cron следущее

    0 7 */10 * * /usr/bin/letsencrypt certonly --debug --webroot -w /home/picloud.ga/ -d picloud.ga --email [email protected] --renew-by-default --agree-tos
    

    На данном этапе проверьте правильно ли Вы поменяли все пути, диск примонтирован (если он есть) и перезагрузитесь. После перезагрузки проверьте все ли службы запустились автоматически systemctl status nginx php7.0-fpm mysql redis-server, если кто-то не запустился и не по причине синтаксической ошибки в конфиге - добавьте его в автозапуск systemctl enable service-name.

    База данных

    Сейчас самое время создать базу данных. Подключимся к mysql root пользователем и создадим базу.

    mysql -uroot -p<пароль_введенный_при_установке>
    

    Создаем базу данных и пользователя базы.

    MariaDB [(none)]> CREATE DATABASE picloud;
    MariaDB [(none)]> GRANT ALL PRIVILEGES ON picloud.* TO 'picloud'@'localhost' IDENTIFIED BY 'sup3r_str0nk_password';
    MariaDB [(none)]> FLUSH PRIVILEGES;
    MariaDB [(none)]> \q
    

    Базовая настройка NextCloud

    Почти все готово. Открываем в браузере наш picloud.ga и видим следующее.

    0_1473629693592_picloud1-2.png

    Введите желаемый логин для админской учетной записи и пароль, затем выберите тип базы данных и параметры подключения (в случае если был выбран MySQL). NextCloud так же может работать и с PostgreSQL, его нет в списке так как мы не устанавливали модуль php-pgsql, я не рассматриваю этот вариант так как в данном случае это “стрелять из пушки по воробъям”.

    SQLite или MySQL/MariaDB?

    SQLite - Огромный плюс такого типа БД заключается в том, что это просто файл, который будет находится в корневой директории NextCloud, вопрос бекапа решается очень просто. Разработчики SQLite заявляют что прошли те времена, когда это был очень медленная СУБД. А вот разработчики NextCloud несмотря на поддержку данного типа БД наоборот, в каждом ответе касающегося баз данных советуют перейти на MySQL, так как он поддерживает многопоточность, а для NextCloud это очень важно, а SQLite источник всех тормозов системы. Решать Вам. Я остановился на MySQL, но откровенно говоря разницы в производительности не заметил.


    Оптимизация и улучшения

    Оптимизация /tmp и /var/log (опционально)

    Так как у microSD карт памяти имеются некоторые проблемы с быстрым умиранием при интенсивной записи мы перенесем логи и /tmp (используется php как временный каталог загрузки) в оперативную память.
    Пропишите в /etc/fstab/

    tmpfs /tmp tmpfs defaults,noatime,nosuid,nodev,noexec,mode=1777,size=512M 0 0
    tmpfs /var/tmp tmpfs defaults,noatime,nosuid,size=30m 0 0
    tmpfs /var/log tmpfs defaults,noatime,nosuid,mode=0755,size=100m 0 0
    tmpfs /var/run tmpfs defaults,noatime,nosuid,mode=0755,size=2m 0 0
    tmpfs /var/spool/mqueue tmpfs defaults,noatime,nosuid,mode=0700,gid=12,size=30m 0 0
    

    Кэш в RAM

    Добавте в /home/picloud.ga/config/config.php перед закрывающей скобкой );

    'memcache.local' => '\\OC\\Memcache\\Redis',
    'filelocking.enabled' => 'true',
    'memcache.distributed' => '\\OC\\Memcache\\Redis',
    'memcache.locking' => '\\OC\\Memcache\\Redis',
    'redis' =>
    array (
    'host' => 'localhost',
    'port' => 6379,
    'timeout' => 0,
    'dbindex' => 0,
    ),
    

    Итоги

    В итоге мы получили дешевое, достаточно надежное и вместительное (в зависимости от выбранного носителя информации) домашнее “облако” для синхронизации своих файлов с любых устройств и любой ОС, с полным контролем над своими данными и дополнительными функциями в виде календаря, контактов и других функций добавляемых при помощи плагинов. Что насчет скорости синхронизации, моя тестовая директория размером 7GB (несколько больших файлов, остальные мелкие (код проектов), в сумме 8 тысяч файлов) синхронизировались около 40 минут. Скорость загрузки страниц веб-интерфейса 1-2 секунды, что в разрез противоречит отзывам найденным при быстром поиске в Google, там это 4-7 секунд. Подозреваю что дело в php-fpm или php7, а может и то и другое.
    Получилось достаточно внушительно. В планах данного проекта - еще больше разогнать скорость работы системы, если это возможно, как минимум собрать RAID0 из флешек, если это даст прирост - тогда и RAID10. А так же хочу попробовать запустить на ODROID-C2 на eMMC или ODROID-XU4 с внешним диском подключенным по USB 3.0. ODROID потому, что в них настоящий гигабитный Ethernet с выделенным контроллером, который выдает 998Mbps в ipref.

    На этом все. Если возникнут вопросы, дополнения и исправления - пишите :)



  • 1

    У данной настройки nextcloud есть большая проблема. Данные для nextcloud и для php-fpm имеют доступ от лица пользователя picloud.ga однако Nginx работает от пользователя www-data. В итоге раздачи статики по данному конфигу не будет(ох я заманался искать в чем проблема…).
    Для нормальной работы необходимо чтобы либо пользователь был в группе www-data либо изменить запуск nginx на пользователя picloud.ga. Первый способ предпочтительнее, но чтобы он работал еще надо файлы сделать доступными для группы chmod -R 0770 /home/picloud.ga/*.
    По факту возможно более адекватное решение не создавать никаких доп пользователей а жить из под www-data как делают везде





Похоже, подключение к PiBoard было разорвано, подождите, пока мы пытаемся восстановить соединение.