Я уже писал про домашний сервер. Настало время разобраться с облаком. Мне хотелось что-то на подобии «Яндекс диска» или «Google Drive». К счастью такая возможность есть и это Nextcloud. Так же немного познакомимся с Docker и настроим службу в Linux. Приступим.
Подготовка
Для начала необходимо подготовить площадку. Так как у меня по сути 2 сервера, то я буду разворачивать приложение, так сказать, на сервер приложений. Чтобы удобно было это делать я буду всю структуру устанавливать в контейнерах. Я про это уже писал в общих чертах, а теперь буду использовать.
И так, нам понадобится система контейнеризации. Для этого буду использовать Docker. Как его устанавливать, настраивать, использовать написано предостаточно. Все будет происходить стандартным способом. Идем на сайт, читаем, изучаем, выбираем свой дистрибутив и устанавливаем по инструкции. Так как у меня Armbian на основе Debian, то я выбираю его и просто все делаю по инструкции.
После этого нам понадобится Docker Compose. Есть так же инструкция по его установке. Но не все так просто! У меня он не заработал. Это все потому, что по умолчанию его бинарная версия собрана для систем x86_64, а на одноплатнике arm64. Это совершенно разные архитектуры. Но отчаиваться не будем. Заходим в консоль и устанавливаем из репозиториев:
apt install -y docker-compose
Версия не последней свежести, но рабочая. Нам этого будет достаточно.
Установка
Теперь нужно создать директории, которые будут использоваться. Для этого выполняем:
mkdir -p /mnt/nfs/cloud/cloud
mkdir -p /mnt/nfs/cloud/db
mkdir -p /opt/nextcloud
Так как у меня подключен сетевой диск по nfs, то создаю я директории именно на нем. Третья команда создает директорию в /opt. В ней я буду располагать файлы работы сервисов.
Далее выполняю nano /opt/nextcloud/docker-compose.yml и наполняю его:
version: "2.4"
services:
db:
image: mariadb:10.7.1-focal
command: --transaction-isolation=READ-COMMITTED --binlog-format=ROW --innodb-file-per-table=1 --skip-innodb-read-only-compressed
restart: always
environment:
MARIADB_DATABASE: "имя БД"
MARIADB_USER: "имя пользователя для БД"
MARIADB_PASSWORD: "пароль БД"
MARIADB_RANDOM_ROOT_PASSWORD: 1
volumes:
- type: bind
source: /mnt/nfs/cloud/db
target: /var/lib/mysql
mem_limit: 256m
mem_reservation: 64m
nextcloud:
image: nextcloud:22.2.3-fpm-alpine
restart: always
volumes:
- type: bind
source: /mnt/nfs/cloud/cloud
target: /var/www/html
mem_limit: 256m
mem_reservation: 64m
links:
- db
depends_on:
- db
nginx:
image: nginx:1.20.1-alpine
restart: always
volumes:
- type: bind
source: /mnt/nfs/cloud/cloud
target: /var/www/html
- type: bind
source: ./nginx.conf
target: /etc/nginx/nginx.conf
ports:
- "8082:80"
links:
- nextcloud
depends_on:
- nextcloud
mem_limit: 128m
mem_reservation: 32m
Этот файл описывает какие образы контейнеров необходимо использовать, как их запускать, как объединять их для взаимодействия по сети и как установить ограничение ресурсов. Все необходимы контейнеры можно найти по адресу hub.docker.com. В данном случае мне нужно 3 контейнера: nextcloud, mariadb и nginx.
Теперь выполняем nano /opt/nextcloud/nginx.conf:
worker_processes auto;
pid /run/nginx.pid;
events {
worker_connections 1024;
multi_accept on;
}
http {
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 15;
types_hash_max_size 2048;
server_tokens off;
include /etc/nginx/mime.types;
default_type text/javascript;
access_log off;
error_log /var/log/nginx/error.log;
gzip on;
gzip_min_length 100;
gzip_http_version 1.1;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
client_max_body_size 8M;
upstream php-handler {
server nextcloud:9000;
}
server {
listen 80;
listen [::]:80;
add_header Referrer-Policy "no-referrer" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Download-Options "noopen" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Permitted-Cross-Domain-Policies "none" always;
add_header X-Robots-Tag "none" always;
add_header X-XSS-Protection "1; mode=block" always;
fastcgi_hide_header X-Powered-By;
root /var/www/html;
location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}
location = /.well-known/carddav {
return 301 $scheme://$host:$server_port/remote.php/dav;
}
location = /.well-known/caldav {
return 301 $scheme://$host:$server_port/remote.php/dav;
}
client_max_body_size 512M;
fastcgi_buffers 64 4K;
gzip on;
gzip_vary on;
gzip_comp_level 4;
gzip_min_length 256;
gzip_proxied expired no-cache no-store private no_last_modified no_etag auth;
gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy;
location / {
rewrite ^ /index.php;
}
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\/.+|oc[ms]-provider\/.+|.+\/richdocumentscode\/proxy)\.php(?:$|\/) {
fastcgi_split_path_info ^(.+?\.php)(\/.*|)$;
set $path_info $fastcgi_path_info;
try_files $fastcgi_script_name =404;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $path_info;
fastcgi_param HTTPS on;
fastcgi_param modHeadersAvailable true;
fastcgi_param front_controller_active true;
fastcgi_pass php-handler;
fastcgi_intercept_errors on;
fastcgi_request_buffering off;
fastcgi_read_timeout 300;
}
location ~ ^\/(?:updater|oc[ms]-provider)(?:$|\/) {
try_files $uri/ =404;
index index.php;
}
gzip_proxied expired no-cache no-store private no_last_modified no_etag auth;
gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy;
location / {
rewrite ^ /index.php;
}
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\/.+|oc[ms]-provider\/.+|.+\/richdocumentscode\/proxy)\.php(?:$|\/) {
fastcgi_split_path_info ^(.+?\.php)(\/.*|)$;
set $path_info $fastcgi_path_info;
try_files $fastcgi_script_name =404;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $path_info;
fastcgi_param HTTPS on;
fastcgi_param modHeadersAvailable true;
fastcgi_param front_controller_active true;
fastcgi_pass php-handler;
fastcgi_intercept_errors on;
fastcgi_request_buffering off;
fastcgi_read_timeout 300;
}
location ~ ^\/(?:updater|oc[ms]-provider)(?:$|\/) {
try_files $uri/ =404;
index index.php;
}
}
}
Это конфигурационный файл для nginx.
Дело в том что сам Nextcloud написан на PHP и основной web-сервер, накотором он работает — это Apache. Но так же может работать в связка php-fpm + nginx. Ну мне так хочется и для этого есть определенный ряд причин, который приходит с опытом. А раз есть образ Nextcloud с php-fpm, то почему бы им не воспользоваться?..
Далее переходим в нужную директорию (если еще не перешли) с помощью cd /opt/nextcloud и все это добро запускаем:
docker-compose -f docker-compose.yml up
Теперь наблюдаем и ждем, как загружаются и запускаются контейнеры. На это может потребоваться достаточно времени, так как распаковка образов происходит на SD-карту, а она не особо быстрая.
После того как все загрузиться и запустится открываем у себя на компьютере локально браузер и вводим адрес http://<ваш IP-адрес вашего сервера>:8082. После все делаем поэтапно: отвечаем на вопросы и наблюдаем за действиями системы. Важно также понимать, что выбираем СУБД MySQL, а адрес сервера указываем db. По факту мы указываем не IP-адрес, а доменное имя. Явно мы его нигде не прописывали, но когда мы перечисляем сервисы в файле, Docker Compose присваивает эти имена адресам и внутри сети Docker все они прекрасно определяются. Так устроена эта контейнеризация.
Как только все будет готово и откроется уже админский аккаунт, браузер закрываем и в консоле на удаленном сервер нажимаем комбинацию Ctrl+C. Ждем пока все контейнеры остановятся.
Демонизация
В таком состоянии облако будет работать пока будет открыта консоль сервера. Но ведь хочется, чтобы он работал постоянно. И эту задачу решить достаточно просто.
Для начала создаем файл командой nano /etc/systemd/system/nextcloud.service и записываем в него следующее:
[Unit]
Description=Nextcloud docker-compose
Requires=docker.service
After=docker.service
[Service]
Restart=always
WorkingDirectory=/opt/nextcloud/
# Compose up
ExecStart=/usr/bin/docker-compose -f docker-compose.yml up
# Compose down, remove containers
ExecStop=/usr/bin/docker-compose -f docker-compose.yml down
[Install]
WantedBy=multi-user.target
Описание сервиса готово. Далее нужно сказать демону демонов (ну так получается), чтобы он обновил свой список демонов:
systemctl daemon-reload
После включаем и запускаем:
systemctl enable nextcloud
systemctl start nextcloud
Посмотреть что демон запущен:
systemctl status nextcloud
Немного ждем и все готово. Можно пользоваться.
Обслуживание системы = хорошая система
В комплекте Nextcloud есть специальный файл, который нужно периодически запускать. Этот файл содержит в себе программный код обслуживания: удаление старых записей, очистка кэша, освобождения места и т.д. Этот файл может работать в 3-х режимах: при каждом запросе на сервер, периодический запрос к этому файлу удаленно, добавление его в планировщик. Я сначала пользовался вторым вариантом, но потом решил перенастроить его именно на локальный планировщик. Суть дела не меняет, но локальный запуск, я считаю, будет более правильным.
Для начала зайдем под паролем администратора в само облако и перейдем в Настройки->Основные параметры. У меня стояло Webcron, так как у меня было настроено так. Теперь я поставил Cron.
После этой манипуляции нужно настроить сам планировщик. Для начала нужно проверить, что все работает правильно. В консоле выполняем:
docker ps
Находим в списке наш запущенный контейнер с сервером. В столбце в моем случае есть строчка nextcloud_nextcloud_1. Такое имя формирует Docker Compose. Если перезапустить службу, то будут созданы новые контейнеры, но Docker Compose присвоит эти же имена. Можно присвоить свои имена. Об этом ищите в документации к Docker и Docker Compose, а меня этот вариант более чем устраивает. По этому имени можно обращаться к запущенному контейнеру. Что нам и нужно.
И Попробуем выполнить:
docker exec -it -u www-data nextcloud_nextcloud_1 php cron.php
Если все прошло успешно, то нужно добавить все это чудо в планировщик. Выполняем crontab -e и добавляем строчку:
5 3 * * * docker exec -u www-data nextcloud_nextcloud_1 php cron.php
Здесь мы говорим планировщику, что запуска задание в 3 часа ночи 5 минут, каждый день.
Закрываем и сохраняем. Готово!
Что получилось?
В админском пользователе можно установить дополнения по вкусу. Я НАСТОЯТЕЛЬНО РЕКОМЕНДУЮ создать обычного пользователя и работать под ним, а админский пользователь останется для настройки и обслуживания.
Ко всему прочему можно «делиться» файлами и папками между облаками назначая различные права доступа. Так же можно зайти на сайт https://scan.nextcloud.com и проверить безопасность, но это можно будет сделать, если у вас есть внешний адрес, доменное имя и облако настроено через него по протоколу HTTPS. А вот об этом я расскажу немного позже. Дело не сложное, но очень полезное.