Содержание
NextCloud + OnlyOffice
Домашняя хранилка у меня представляет малюсенький ПК (Terramaster f4-423) с 4 дисками в RAID-10,
большинство ресурсов доступны только из локальной сети, но вот появилась необходимость редактировать документики (таблички)
и синхронизировать папки через приложение, это немного не сетевая папка, а именно синхронизация, когда нет интернета папка доступна, а когда интернет появляется, то она синхронизируется и обновляется.
Общая архитектура
- Debian
- На хосте стоит nginx, он проксирует в кучу контейнеров
- Стоит certbot, который автоматом обновляет сетификаты lets-encrypt
- MariaDB стоит на хосте, там постоянное хранение баз данных для моих домашних сервисов
- Ну и естественно - есть докер на котором всё на свете крутится
- Комп за роутером
про установку certbot
Установка mariadb
Установка докера
Инструкция по раскатке на докер-хабе
Инструкция создана частичнео при использовании ИИ,
но, приходилось читать документации и скармливать примеры настроек…
Создадим конфиг
Мы применяем очень интересную технологию, когда у вас есть .env файл в котором прописаны все домены, порты, пароли…
И все команды задействуют эти переменные, самое главное это docker-compose, который не содержит секретов, а дергает из переменных при раскатке.
При таком подходе можно смело просить что-то переделать ИИ-ботов, не отправляя им секретных данных, \\ну и писать подобные статьи с листингами, не боясь опубликовать что-то секретное!!!
ENV="/storage/DockerApps/nextCloud/.env" mkdir -p /storage/DockerApps/nextCloud touch $ENV chmod 600 $ENV # --- Сеть --- grep -q "^DB_HOST=" $ENV || echo 'DB_HOST="172.22.0.1"' >> $ENV grep -q "^NETWORK_NAME=" $ENV || echo 'NETWORK_NAME="nextcloud_net"' >> $ENV grep -q "^NETWORK_SUBNET=" $ENV || echo 'NETWORK_SUBNET="172.22.0.0/16"' >> $ENV grep -q "^DB_HOST_SUBNET=" $ENV || echo 'DB_HOST_SUBNET="172.22.%"' >> $ENV # 🔴 Домен Nextcloud (уникальное имя) grep -q "^DOMAIN_NC=" $ENV || echo 'DOMAIN_NC="oblako.example.com"' >> $ENV # 🔴 Домен OnlyOffice (уникальное имя) grep -q "^DOMAIN_OO=" $ENV || echo 'DOMAIN_OO="office.oblako.example.com"' >> $ENV # --- Порт Apache в контейнере --- grep -q "^APACHE_HOST_PORT=" $ENV || echo 'APACHE_HOST_PORT="9104"' >> $ENV # --- Порт OnlyOffice в контейнере --- grep -q "^OO_HOST_PORT=" $ENV || echo 'OO_HOST_PORT="8081"' >> $ENV # --- База данных --- grep -q "^DB_NAME=" $ENV || echo 'DB_NAME="nextcloud"' >> $ENV grep -q "^DB_USER=" $ENV || echo 'DB_USER="nextcloud"' >> $ENV grep -q "^DB_PASS=" $ENV || echo "DB_PASS=\"$(pwgen -s 32 1)\"" >> $ENV # --- Nextcloud --- grep -q "^NEXTCLOUD_ADMIN_USER=" $ENV || echo 'NEXTCLOUD_ADMIN_USER="admin"' >> $ENV grep -q "^NEXTCLOUD_ADMIN_PASSWORD=" $ENV || echo "NEXTCLOUD_ADMIN_PASSWORD=\"$(pwgen -s 24 1)\"" >> $ENV # --- Redis --- grep -q "^REDIS_PASSWORD=" $ENV || echo "REDIS_PASSWORD=\"$(pwgen -s 32 1)\"" >> $ENV # --- OnlyOffice --- grep -q "^ONLYOFFICE_JWT_SECRET=" $ENV || echo "ONLYOFFICE_JWT_SECRET=\"$(pwgen -s 32 1)\"" >> $ENV echo "✅ .env файл создан и заполнен. Проверьте и отредактируйте его."
Далее откроем файл
/storage/DockerApps/nextCloud/.env
и отредактируем хосты/домены/юзеров…
Создаем подсеть
Если на данном этапе что-то не удалось, например подсеть занята, то идем к прошлому шагу и меняем всё что относится к подсетям
от этого зависит какого пользователя БД создавать и всё остальное.
source /storage/DockerApps/nextCloud/.env # Убедитесь, что переменные экспортированы docker network create \ --driver=bridge \ --subnet=${NETWORK_SUBNET} \ --gateway=172.22.0.1 \ ${NETWORK_NAME}
Проверка
docker network inspect ${NETWORK_NAME} --format=' Сеть: {{.Name}} Драйвер: {{.Driver}} Подсеть: {{range .IPAM.Config}}{{.Subnet}}{{end}} Шлюз: {{range .IPAM.Config}}{{.Gateway}}{{end}} '
Создаем базу данных, пользователя...
source /storage/DockerApps/nextCloud/.env
Проверим что все переменные заполнились корректно
echo "База: ${DB_NAME}" echo "Пользователь: ${DB_USER}" echo "Хост: ${DB_HOST}" echo "Подсеть: ${DB_HOST_SUBNET}"
Создадим базу, пользователя
mariadb -e "CREATE DATABASE IF NOT EXISTS ${DB_NAME} CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;" mariadb -e "CREATE USER IF NOT EXISTS '${DB_USER}'@'${DB_HOST_SUBNET}' IDENTIFIED BY '${DB_PASS}';" mariadb -e "GRANT ALL PRIVILEGES ON ${DB_NAME}.* TO '${DB_USER}'@'${DB_HOST_SUBNET}';" mariadb -e "FLUSH PRIVILEGES;" mariadb -e "SELECT User, Host FROM mysql.user WHERE User='${DB_USER}';"
Создадим контейнер NextCloud
Сперва создадим все каталоги (замените на своё), у меня в storage просто примонтирован raid-10 и там весь хлам…
# Основной каталог приложения mkdir -p /storage/DockerApps/nextCloud/{nextcloud/{html,config},redis,onlyoffice/{logs,data,fonts}} mkdir -p /storage/nextCloud_data # Для данных пользователей # Права доступа (www-data в контейнерах использует UID/GID 33) chown -R 33:33 /storage/nextCloud_data chmod -R 750 /storage/nextCloud_data chown -R 33:33 /storage/DockerApps/nextCloud/nextcloud/html chmod -R 755 /storage/DockerApps/nextCloud/nextcloud/html chown -R 33:33 /storage/DockerApps/nextCloud/nextcloud/config/ chmod -R 750 /storage/DockerApps/nextCloud/nextcloud/config/ chown -R 33:33 /storage/DockerApps/nextCloud/onlyoffice chmod -R 750 /storage/DockerApps/nextCloud/onlyoffice chown -R 33:33 /storage/DockerApps/nextCloud/redis chmod -R 750 /storage/DockerApps/nextCloud/redis
Проверим
tree -L 3 /storage/DockerApps/nextCloud/
Получается что-то такое…
/storage/DockerApps/nextCloud/ ├── nextcloud │ ├── config │ └── html ├── onlyoffice │ ├── data │ ├── fonts │ └── logs └── redis
/storage/DockerApps/nextCloud/docker-compose.yml
version: '3.8' services: redis: image: redis:alpine container_name: nc_redis restart: always networks: - nextcloud_net command: redis-server --requirepass ${REDIS_PASSWORD} volumes: - ./redis:/data nextcloud-apache: image: nextcloud:apache container_name: nc_apache restart: always depends_on: - redis networks: - nextcloud_net ports: - "127.0.0.1:${APACHE_HOST_PORT}:80" volumes: - ./nextcloud/html:/var/www/html - /storage/nextCloud_data:/var/www/html/data - ./nextcloud/config:/var/www/html/config # Монтируем конфигурацию Apache для доверия заголовкам X-Forwarded-Proto - ./apache-conf/remoteip.conf:/etc/apache2/conf-enabled/remoteip.conf environment: - MYSQL_HOST=${DB_HOST} - MYSQL_DATABASE=${DB_NAME} - MYSQL_USER=${DB_USER} - MYSQL_PASSWORD=${DB_PASS} - REDIS_HOST=redis - REDIS_HOST_PASSWORD=${REDIS_PASSWORD} - NEXTCLOUD_ADMIN_USER=${NEXTCLOUD_ADMIN_USER} - NEXTCLOUD_ADMIN_PASSWORD=${NEXTCLOUD_ADMIN_PASSWORD} - NEXTCLOUD_TRUSTED_DOMAINS=${DOMAIN_NC} - PHP_MEMORY_LIMIT=512M - PHP_UPLOAD_LIMIT=10G onlyoffice-document-server: image: onlyoffice/documentserver:latest container_name: nc_onlyoffice restart: always networks: - nextcloud_net volumes: - ./onlyoffice/logs:/var/log/onlyoffice - ./onlyoffice/data:/var/www/onlyoffice/Data - ./onlyoffice/fonts:/usr/share/fonts/truetype/custom environment: - JWT_ENABLED=true - JWT_SECRET=${ONLYOFFICE_JWT_SECRET} - JWT_HEADER=AuthorizationJwt ports: - "127.0.0.1:${OO_HOST_PORT}:80" networks: nextcloud_net: external: true name: ${NETWORK_NAME}
Далее конфиг для apache, чтобы он себя адекватно вел за nginx, не пытался куда то редиректить и говорить что мы не безопасно подключены…
cd /storage/DockerApps/nextCloud mkdir apache-conf chown 33:33 apache-conf/ chmod 755 apache-conf/ nano /storage/DockerApps/nextCloud/apache-conf/remoteip.conf
/storage/DockerApps/nextCloud/apache-conf/remoteip.conf
# Настраиваем Apache на доверие заголовкам от Nginx RemoteIPHeader X-Forwarded-For # Укажи ТОЛЬКО корректные IP-адреса/подсети, с которых Nginx делает proxy_pass # Обычно это IP хоста в Docker-сети и/или localhost (если docker-proxy привязан к 127.0.0.1) RemoteIPTrustedProxy 127.0.0.1 RemoteIPTrustedProxy 172.22.0.1 # Устанавливаем переменные окружения на основе заголовков SetEnvIf X-Forwarded-Proto "^https$" HTTPS=on SetEnvIf X-Forwarded-Proto "^https$" REQUEST_SCHEME=https SetEnvIf X-Forwarded-Port "^(.*)$" REQUEST_PORT=$1
Запускаем контейнеры
cd /storage/DockerApps/nextCloud docker compose up -d
Ждем пока установится, наблюдаем за логами
docker logs -f nc_apache
Вас должно встречать что-то такое, процесс длится минуту-две
Configuring Redis as session handler Initializing nextcloud 33.0.0.16 ... New nextcloud instance Installing with MySQL database => Searching for hook scripts (*.sh) to run, located in the folder "/docker-entrypoint-hooks.d/pre-installation" ==> Skipped: the "pre-installation" folder is empty (or does not exist) Starting nextcloud installation
Если по какой то причине процесс не завершился, то при рестарте он не завершится и будут всякие проблемки, тут надо и nextCloud_data чистить (или переносить) и html и config папки или руками стартовать
Смотрим логи
docker logs nc_apache docker logs nc_onlyoffice docker logs nc_redis
Решение проблем
Если установка не прошла, то ее можно руками запустить
docker exec -u www-data nc_apache php occ maintenance:install \ --database "mysql" \ --database-host "${DB_HOST}" \ --database-name "${DB_NAME}" \ --database-user "${DB_USER}" \ --database-pass "${DB_PASS}" \ --admin-user "${NEXTCLOUD_ADMIN_USER}" \ --admin-pass "${NEXTCLOUD_ADMIN_PASS}"
Узнать статус установки
docker exec -u www-data nc_apache php occ status
Так проверить трастовый домен если не пускает…
docker exec -u www-data nc_apache php occ config:system:get trusted_domains
А так можно добавить…
docker exec -u www-data nc_apache php occ config:system:set trusted_domains 1 --value="${DOMAIN_NC}"
Настроим nginx
Генерим конфиги примерно так на onlyoffice пока не понял как спрятать домен, кажется что у них взаимодействие идет через фронт
source /storage/DockerApps/nextCloud/.env cat > /etc/nginx/sites-available/nextcloud << EOF # http -> https redirect server { listen 80; listen [::]:80; server_name ${DOMAIN_NC}; # Enforce HTTPS return 301 https://\$server_name\$request_uri; } server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name ${DOMAIN_NC}; # SSL certificates (полученные через Certbot) ssl_certificate /etc/letsencrypt/live/${DOMAIN_NC}/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/${DOMAIN_NC}/privkey.pem; # Prevent nginx HTTP Server Detection server_tokens off; # HSTS settings (опционально) # add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always; # set max upload size and increase upload timeout: client_max_body_size 512M; client_body_timeout 300s; # Enable gzip 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 text/javascript application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/wasm 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; # HTTP response headers borrowed from Nextcloud \`.htaccess\` add_header Referrer-Policy "no-referrer" always; add_header X-Content-Type-Options "nosniff" always; add_header X-Frame-Options "SAMEORIGIN" always; add_header X-Permitted-Cross-Domain-Policies "none" always; add_header X-Robots-Tag "noindex, nofollow" always; location / { proxy_pass http://127.0.0.1:${APACHE_HOST_PORT}; # Порт Apache в контейнере # Заголовки для правильной работы proxy_set_header Host \$host; proxy_set_header X-Real-IP \$remote_addr; proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto \$scheme; # ВАЖНО для HTTPS proxy_set_header X-Forwarded-Port \$server_port; # ВАЖНО для HTTPS proxy_set_header X-Forwarded-Host \$server_name; # Таймауты proxy_connect_timeout 600s; proxy_send_timeout 600s; proxy_read_timeout 600s; # Буферизация proxy_buffering off; proxy_request_buffering off; } } EOF
cat > /etc/nginx/sites-available/onlyoffice << EOF # http -> https redirect server { listen 80; listen [::]:80; server_name ${DOMAIN_OO}; return 301 https://\$server_name\$request_uri; } # HTTPS server server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name ${DOMAIN_OO}; # SSL certificates (полученные через Certbot) ssl_certificate /etc/letsencrypt/live/${DOMAIN_OO}/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/${DOMAIN_OO}/privkey.pem; # Отключение отображения версии nginx server_tokens off; # ЕДИНСТВЕННЫЙ location блок, проксирующий всё в OnlyOffice location / { proxy_pass http://127.0.0.1:${OO_HOST_PORT}; # Порт OnlyOffice в контейнере # Обычные заголовки proxy_set_header Host \$host; proxy_set_header X-Real-IP \$remote_addr; proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto \$scheme; proxy_set_header X-Forwarded-Host \$server_name; # Настройки для WebSocket proxy_set_header Upgrade \$http_upgrade; proxy_set_header Connection "upgrade"; proxy_read_timeout 3600s; proxy_send_timeout 3600s; proxy_connect_timeout 3600s; # Буферизация proxy_buffering off; proxy_request_buffering off; } } EOF
Включаем сайты
ln -s /etc/nginx/sites-available/nextcloud /etc/nginx/sites-enabled/ ln -s /etc/nginx/sites-available/onlyoffice /etc/nginx/sites-enabled/ # Проверим синтаксис nginx -t # Перезагрузим Nginx systemctl reload nginx
Certbot
Чтобы не мучаться с сертификатами, просто удаляете из конфигов секции с listen 80, а 443 переделываете на 80, убираете все пункты с путями на серты и выполняете команду в стиле
certbot --nginx -d onlyoffice.example.com --email admin@example.com --agree-tos --non-interactive --redirect
у вас и сертификаты получит и редирект с 80 порта сделает и весь конфиг подправит на серты
Первичные настройки Nextcloud (onlyoffice)
Сперва заходим на сайт onlyoffice, там вы должны увидеть что то такое
Теперь идем в nextcloud, заходим под паролем, который у вас лежит в .env
В правом углу заходим в пункт приложения
Заходим в офис и там сверху выбираем плашку OnlyOffice, ждем пока сверху всплывет уведомление что он устанеовлен
Теперь идем в параметры сервера
Там выбираем nextcloud слева onlyoffice
Просто указываем наш адрес DOMAIN_OO и токен ONLYOFFICE_JWT_SECRET из файла .env заголовок - AuthorizationJwt
Решение проблем с редактированием
Я столкнулся с таким, что кнопочка сохранения сама пропадает после изменения, но файл на диске не сохраняется
И вот стоит закрыть вкладку и скачать файл - он не изменен
Но проходит секунд 30 и ура файл обновился, т.е. какое то отслеживание что я перестал с файлом работать и его сохранение.
Мне захотелось чтобы файл гарантированно сохранялся, и что странно вот эта галочка с принудительным сохранением помогает, перед тем как закрыть файл я жсу ctrl+s






