Недавно потестировал Nexcloud вообще, см. NextCloud: установка сервера на Debian с NGINX и PHP-FPM, и клиента на Arch Linux — в целом понравилось, работает — можно попробовать мигрировать с Dropbox на него.
Сегодня запустим Nextcloud полностью в Docker, на сервере с Debian 10 в Digital Ocean.
К серверу подключён отдельный диск, на котором будут все данные Nextcloud, что бы можно легко забекапить/перенести их.
Для запуска создадим Docker Compose стек, в котором будут:
- NGINX: проксирующий веб-сервер
- Lets Encrypt: клиент для генерации и обновления SSL-сертификатов
- MariaDB: сервер баз данных для хранения настроек Nextcloud
- Nextcloud: контейнер с PHP-FPM и исходным кодом Nextclou
Документация — тут>>>.
Для SSL используем клиент Lets Encrypt из docker-образа docker-letsencrypt-nginx-proxy-companion.
Содержание
Установка Docker и Docker Compose
Устанавливаем Docker:
[simterm]
root@setevoy-do-nextcloud-production:~# curl https://get.docker.com/ | bash
[/simterm]
И Docker Compose (проверьте версию — download/1.24.1/ на странице релизов):
[simterm]
root@setevoy-do-nextcloud-production:~# curl -L "https://github.com/docker/compose/releases/download/1.24.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose root@setevoy-do-nextcloud-production:~# chmod +x /usr/local/bin/docker-compose
[/simterm]
Создаём каталог для файла Compose:
[simterm]
root@setevoy-do-nextcloud-production:~# mkdir /opt/nextcloud root@setevoy-do-nextcloud-production:~# cd /opt/nextcloud/
[/simterm]
Приступаем к созданию стека.
Запуск Nexcloud
nginx-proxy
Создаём каталоги для файлов NGINX и Lets Encrypt:
[simterm]
root@setevoy-do-nextcloud-production:/data/nextcloud# mkdir -p /data/nextcloud/nginx/{certs,vhost.d,html}
[/simterm]
Создаём файл /opt/nextcloud/nextcloud-compose.yml
, начнём с конца — добавляем сеть:
networks: nextcloud_network:
Теперь добавляем контейнер с nginx-proxy
, который использует эту сеть, монтируем каталоги и приводим файл к такому виду:
version: '3' services: nginx-proxy: image: jwilder/nginx-proxy:alpine labels: - "com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy=true" container_name: nextcloud-proxy networks: - nextcloud_network ports: - 80:80 - 443:443 volumes: - /data/nextcloud/nginx/vhost.d:/etc/nginx/vhost.d:rw - /data/nextcloud/nginx/html:/usr/share/nginx/html:rw - /data/nextcloud/nginx/certs:/etc/nginx/certs:ro - /etc/localtime:/etc/localtime:ro - /var/run/docker.sock:/tmp/docker.sock:ro restart: unless-stopped networks: nextcloud_network:
Строка labels: com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy=true будет использоваться контейнером с Lets Encrypt, что бы определить «свой» прокси-сервис.
Каталоги, которые монтируем:
/etc/nginx/certs
: для хранения сертификатов и приватных ключей (read-only для контейнераnginx-proxy
, т.к. файлы создаются контейнером с клиентом Lets Encrypt)./etc/nginx/vhost.d
: для настройки виртуалхостов/usr/share/nginx/html
: для верификации домена при генерации сертификата
Запускаем:
[simterm]
root@setevoy-do-nextcloud-production:/opt/nextcloud# docker-compose -f nextcloud-compose.yml up Creating nextcloud-proxy ... done Attaching to nextcloud-proxy nextcloud-proxy | WARNING: /etc/nginx/dhparam/dhparam.pem was not found. A pre-generated dhparam.pem will be used for now while a new one nextcloud-proxy | is being generated in the background. Once the new dhparam.pem is in place, nginx will be reloaded. nextcloud-proxy | forego | starting dockergen.1 on port 5000 nextcloud-proxy | forego | starting nginx.1 on port 5100 nextcloud-proxy | Generating DH parameters, 2048 bit long safe prime, generator 2 nextcloud-proxy | dockergen.1 | 2019/11/27 08:15:10 Generated '/etc/nginx/conf.d/default.conf' from 1 containers nextcloud-proxy | dockergen.1 | 2019/11/27 08:15:10 Running 'nginx -s reload' nextcloud-proxy | dockergen.1 | 2019/11/27 08:15:10 Watching docker events nextcloud-proxy | dockergen.1 | 2019/11/27 08:15:10 Contents of /etc/nginx/conf.d/default.conf did not change. Skipping notification 'nginx -s reload' nextcloud-proxy | 2019/11/27 08:15:41 [notice] 41#41: signal process started nextcloud-proxy | This is going to take a long time nextcloud-proxy | dhparam generation complete, reloading nginx
[/simterm]
И пробуем подключиться к хосту:
[simterm]
[setevoy@setevoy-arch-work ~] $ curl -I cloud.example.org.ua HTTP/1.1 503 Service Temporarily Unavailable Server: nginx/1.17.5 Date: Wed, 27 Nov 2019 07:57:28 GMT Content-Type: text/html Content-Length: 197 Connection: keep-alive
[/simterm]
Отлично. Ошибка 503 нам сейчас не важна, т.к. кроме NGINX ещё ничего не запущено.
Let’s Encrypt Docker
Добавляем сервис в наш Compose-файл:
... letsencrypt: image: jrcs/letsencrypt-nginx-proxy-companion container_name: nextcloud-letsencrypt depends_on: - nginx-proxy networks: - nextcloud_network volumes: - /data/nextcloud/nginx/vhost.d:/etc/nginx/vhost.d:rw - /data/nextcloud/nginx/html:/usr/share/nginx/html:rw - /data/nextcloud/nginx/certs:/etc/nginx/certs:rw - /etc/localtime:/etc/localtime:ro - /var/run/docker.sock:/var/run/docker.sock:ro restart: unless-stopped ...
Перезапускаем стек:
[simterm]
root@setevoy-do-nextcloud-production:/opt/nextcloud# docker-compose -f nextcloud-compose.yml up Starting nextcloud-proxy ... done Creating nextcloud-letsencrypt ... done Attaching to nextcloud-proxy, nextcloud-letsencrypt nextcloud-proxy | Custom dhparam.pem file found, generation skipped nextcloud-proxy | forego | starting dockergen.1 on port 5000 nextcloud-proxy | forego | starting nginx.1 on port 5100 nextcloud-proxy | dockergen.1 | 2019/11/27 08:31:01 Contents of /etc/nginx/conf.d/default.conf did not change. Skipping notification 'nginx -s reload' nextcloud-proxy | dockergen.1 | 2019/11/27 08:31:01 Watching docker events nextcloud-proxy | dockergen.1 | 2019/11/27 08:31:01 Contents of /etc/nginx/conf.d/default.conf did not change. Skipping notification 'nginx -s reload' nextcloud-proxy | dockergen.1 | 2019/11/27 08:31:02 Received event start for container 2f40fa5f50ea nextcloud-proxy | dockergen.1 | 2019/11/27 08:31:02 Contents of /etc/nginx/conf.d/default.conf did not change. Skipping notification 'nginx -s reload' nextcloud-letsencrypt | Generating a RSA private key nextcloud-letsencrypt | ...........................................................................................................................++++ nextcloud-letsencrypt | ...........++++ nextcloud-letsencrypt | writing new private key to '/etc/nginx/certs/default.key.new' nextcloud-letsencrypt | ----- nextcloud-letsencrypt | Info: a default key and certificate have been created at /etc/nginx/certs/default.key and /etc/nginx/certs/default.crt. nextcloud-letsencrypt | Info: Creating Diffie-Hellman group in the background. nextcloud-letsencrypt | A pre-generated Diffie-Hellman group will be used for now while the new one nextcloud-letsencrypt | is being created. nextcloud-letsencrypt | Generating DH parameters, 2048 bit long safe prime, generator 2 nextcloud-letsencrypt | Reloading nginx proxy (2e665ad175d4e2dbd270b4616bbe5d0e1c5f78421d25da55d163cc15836e859c)... nextcloud-letsencrypt | 2019/11/27 08:31:03 Generated '/etc/nginx/conf.d/default.conf' from 2 containers nextcloud-letsencrypt | 2019/11/27 08:31:03 [notice] 34#34: signal process started nextcloud-letsencrypt | 2019/11/27 08:31:03 Generated '/app/letsencrypt_service_data' from 2 containers nextcloud-letsencrypt | 2019/11/27 08:31:03 Running '/app/signal_le_service' nextcloud-letsencrypt | 2019/11/27 08:31:04 Watching docker events nextcloud-letsencrypt | 2019/11/27 08:31:04 Contents of /app/letsencrypt_service_data did not change. Skipping notification '/app/signal_le_service' nextcloud-letsencrypt | Sleep for 3600s nextcloud-letsencrypt | This is going to take a long time nextcloud-letsencrypt | Info: Diffie-Hellman group creation complete, reloading nginx. nextcloud-letsencrypt | Reloading nginx proxy (2e665ad175d4e2dbd270b4616bbe5d0e1c5f78421d25da55d163cc15836e859c)... nextcloud-letsencrypt | 2019/11/27 08:31:12 Contents of /etc/nginx/conf.d/default.conf did not change. Skipping notification '' nextcloud-letsencrypt | 2019/11/27 08:31:12 [notice] 54#54: signal process started
[/simterm]
Let’s Encrypt сгенерировал сертификат — проверяем:
[simterm]
root@setevoy-do-nextcloud-production:/data/nextcloud# ll /data/nextcloud/nginx/certs/ total 12 -rw-r--r-- 1 root root 1870 Nov 27 08:31 default.crt -rw-r--r-- 1 root root 3272 Nov 27 08:31 default.key -rw-r--r-- 1 root root 424 Nov 27 08:31 dhparam.pem
[/simterm]
Проверяем доступность по HTTPS/443:
[simterm]
[setevoy@setevoy-arch-work ~] $ curl -I https://cloud.example.org.ua curl: (60) SSL certificate problem: self signed certificate More details here: https://curl.haxx.se/docs/sslcerts.html curl failed to verify the legitimacy of the server and therefore could not establish a secure connection to it. To learn more about this situation and how to fix it, please visit the web page mentioned above.
[/simterm]
Окей — соединение проходит, но ругается на сертификат. Исправим это, когда будем запускать контейнер с nextcloud
.
Пока можно использовать curl -k
:
[simterm]
[setevoy@setevoy-arch-work ~] $ curl -kI https://cloud.example.org.ua HTTP/2 503 server: nginx/1.17.5 date: Wed, 27 Nov 2019 08:32:58 GMT content-type: text/html content-length: 197
[/simterm]
Прежняя 503, но главное — коннект на HTTPS проходит, тут всё работает.
MariaDB в Docker
Теперь добавим контейнер с MariaDB.
Что бы хранить данные постоянно — создаём каталог:
[simterm]
root@setevoy-do-nextcloud-production:/data/nextcloud# mkdir /data/nextcloud/mysql
[/simterm]
Добавляем описание сервиса в Compose:
... mysql: image: mariadb container_name: nextcloud-mysql networks: - nextcloud_network volumes: - /data/nextcloud/mysql:/var/lib/mysql - /etc/localtime:/etc/localtime:ro environment: - MYSQL_ROOT_PASSWORD=mysql-root-p@ssw0rd - MYSQL_PASSWORD=nextcloud-p@ssw0rd - MYSQL_DATABASE=nextcloud - MYSQL_USER=nextcloud restart: unless-stopped ...
Запускаем сервис:
[simterm]
... nextcloud-mysql | 2019-11-27 09:16:38+00:00 [Note] [Entrypoint]: Database files initialized nextcloud-mysql | 2019-11-27 09:16:38+00:00 [Note] [Entrypoint]: Starting temporary server nextcloud-mysql | 2019-11-27 09:16:38+00:00 [Note] [Entrypoint]: Waiting for server startup nextcloud-mysql | 2019-11-27 9:16:38 0 [Note] mysqld (mysqld 10.4.10-MariaDB-1:10.4.10+maria~bionic) starting as process 121 ... nextcloud-mysql | 2019-11-27 9:16:38 0 [Note] InnoDB: Using Linux native AIO nextcloud-mysql | 2019-11-27 9:16:38 0 [Note] InnoDB: Mutexes and rw_locks use GCC atomic builtins nextcloud-mysql | 2019-11-27 9:16:38 0 [Note] InnoDB: Uses event mutexes nextcloud-mysql | 2019-11-27 9:16:38 0 [Note] InnoDB: Compressed tables use zlib 1.2.11 nextcloud-mysql | 2019-11-27 9:16:38 0 [Note] InnoDB: Number of pools: 1 nextcloud-mysql | 2019-11-27 9:16:38 0 [Note] InnoDB: Using SSE2 crc32 instructions nextcloud-mysql | 2019-11-27 9:16:38 0 [Note] mysqld: O_TMPFILE is not supported on /tmp (disabling future attempts) nextcloud-mysql | 2019-11-27 9:16:38 0 [Note] InnoDB: Initializing buffer pool, total size = 256M, instances = 1, chunk size = 128M nextcloud-mysql | 2019-11-27 9:16:38 0 [Note] InnoDB: Completed initialization of buffer pool nextcloud-mysql | 2019-11-27 9:16:38 0 [Note] InnoDB: If the mysqld execution user is authorized, page cleaner thread priority can be changed. See the man page of setpriority(). nextcloud-mysql | 2019-11-27 9:16:38 0 [Note] InnoDB: 128 out of 128 rollback segments are active. nextcloud-mysql | 2019-11-27 9:16:38 0 [Note] InnoDB: Creating shared tablespace for temporary tables nextcloud-mysql | 2019-11-27 9:16:38 0 [Note] InnoDB: Setting file './ibtmp1' size to 12 MB. Physically writing the file full; Please wait ... nextcloud-mysql | 2019-11-27 9:16:38 0 [Note] InnoDB: File './ibtmp1' size is now 12 MB. nextcloud-mysql | 2019-11-27 9:16:38 0 [Note] InnoDB: Waiting for purge to start nextcloud-mysql | 2019-11-27 9:16:38 0 [Note] InnoDB: 10.4.10 started; log sequence number 139827; transaction id 21 nextcloud-mysql | 2019-11-27 9:16:38 0 [Note] Plugin 'FEEDBACK' is disabled. nextcloud-mysql | 2019-11-27 9:16:38 0 [Note] InnoDB: Loading buffer pool(s) from /var/lib/mysql/ib_buffer_pool nextcloud-mysql | 2019-11-27 9:16:38 0 [Warning] 'user' entry 'root@de5e3e9dd106' ignored in --skip-name-resolve mode. nextcloud-mysql | 2019-11-27 9:16:38 0 [Warning] 'user' entry '@de5e3e9dd106' ignored in --skip-name-resolve mode. nextcloud-mysql | 2019-11-27 9:16:38 0 [Warning] 'proxies_priv' entry '@% root@de5e3e9dd106' ignored in --skip-name-resolve mode. nextcloud-mysql | 2019-11-27 9:16:38 0 [Note] InnoDB: Buffer pool(s) load completed at 191127 9:16:38 nextcloud-mysql | 2019-11-27 9:16:38 0 [Note] Reading of all Master_info entries succeeded nextcloud-mysql | 2019-11-27 9:16:38 0 [Note] Added new Master_info '' to hash table nextcloud-mysql | 2019-11-27 9:16:38 0 [Note] mysqld: ready for connections. nextcloud-mysql | Version: '10.4.10-MariaDB-1:10.4.10+maria~bionic' socket: '/var/run/mysqld/mysqld.sock' port: 0 mariadb.org binary distribution nextcloud-mysql | 2019-11-27 09:16:39+00:00 [Note] [Entrypoint]: Temporary server started. ...
[/simterm]
Проверяем данные на диске:
[simterm]
root@setevoy-do-nextcloud-production:~# ll /data/nextcloud/mysql/ total 122936 -rw-rw---- 1 systemd-coredump systemd-coredump 32768 Nov 27 09:17 aria_log.00000001 -rw-rw---- 1 systemd-coredump systemd-coredump 52 Nov 27 09:17 aria_log_control -rw-rw---- 1 systemd-coredump systemd-coredump 6176 Nov 27 09:17 ib_buffer_pool -rw-rw---- 1 systemd-coredump systemd-coredump 12582912 Nov 27 09:17 ibdata1 -rw-rw---- 1 systemd-coredump systemd-coredump 50331648 Nov 27 09:17 ib_logfile0 -rw-rw---- 1 systemd-coredump systemd-coredump 50331648 Nov 27 09:16 ib_logfile1 -rw-rw---- 1 systemd-coredump systemd-coredump 12582912 Nov 27 09:17 ibtmp1 -rw-rw---- 1 systemd-coredump systemd-coredump 0 Nov 27 09:16 multi-master.info drwx------ 2 systemd-coredump systemd-coredump 4096 Nov 27 09:17 mysql drwx------ 2 systemd-coredump systemd-coredump 4096 Nov 27 09:17 nextcloud drwx------ 2 systemd-coredump systemd-coredump 4096 Nov 27 09:16 performance_schema
[/simterm]
Всё есть.
Пробуем подключиться локально:
[simterm]
root@setevoy-do-nextcloud-production:/data/nextcloud# mysql -h localhost -u root ... MariaDB [(none)]>
[/simterm]
ОК, работает.
Nextcloud
И, наконец-то — добавляем сам Nextcloud.
Создаём каталоги для него:
[simterm]
root@setevoy-do-nextcloud-production:~# mkdir -p /data/nextcloud/app/{config,custom_apps,data,themes,html}
[/simterm]
Обновляем Compose:
... nextcloud-app: image: nextcloud:latest container_name: nextcloud-app networks: - nextcloud_network depends_on: - letsencrypt - nginx-proxy - mysql volumes: - /data/nextcloud/app/html:/var/www/html - /data/nextcloud/app/config:/var/www/html/config - /data/nextcloud/app/custom_apps:/var/www/html/custom_apps - /data/nextcloud/app/data:/var/www/html/data - /data/nextcloud/app/themes:/var/www/html/themes - /etc/localtime:/etc/localtime:ro environment: - VIRTUAL_HOST=cloud.example.org.ua - LETSENCRYPT_HOST=cloud.example.org.ua - [email protected] restart: unless-stopped ...
Переменная VIRTUAL_HOST
используется nginx-proxy
для выбора направления что и куда проксировать, а LETSENCRYPT_HOST
— самим Lets Encrypt контейнером для выбора имени хоста, для которого будет сгенерирован сертификат. См. документацию тут>>>.
Запускаем стек:
[simterm]
root@setevoy-do-nextcloud-production:/opt/nextcloud# docker-compose -f nextcloud-compose.yml up --force-recreate Recreating nextcloud-proxy ... done Recreating nextcloud-mysql ... done Recreating nextcloud-letsencrypt ... done Creating nextcloud-app ... done Attaching to nextcloud-mysql, nextcloud-proxy, nextcloud-letsencrypt, nextcloud-app ...
[/simterm]
Проверяем по HTTPS, но уже без -k
, т.е. выполняем валидацию сертификата:
[simterm]
[setevoy@setevoy-arch-work ~] $ curl -I https://cloud.example.org.ua HTTP/2 200 server: nginx/1.17.5 ...
[/simterm]
И в браузере:
Настройка Nextcloud
Далее всё выполняется аналогично NextCloud: установка сервера на Debian с NGINX и PHP-FPM, и клиента на Arch Linux, с той разницей, что адрес сервера баз данных указываем в том виде, в котором он указан в Compose-файле, т.е. в данном примере mysql — Docker сам выполнит DNS-resolution по имени контейнера в его IP из сети nextcloud_network
:
И:
Tags и полный docker-compose файл
Перед тем, как закончить со всем этим — давайте обновим Compose-файл, и вместо latest зададим конкретные теги (версии) для запускаемых сервисов — хорошая практика для любого production-ready решения.
На момент написания теги:
- jwilder/nginx-proxy:0.4.0
- jrcs/letsencrypt-nginx-proxy-companion:v1.12
- mariadb:10.4.10
- nextcloud:17.0.1-apache
Весь файл сейчас выглядит так:
version: '3' services: nginx-proxy: image: jwilder/nginx-proxy:0.4.0 labels: - "com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy=true" container_name: nextcloud-proxy networks: - nextcloud_network ports: - 80:80 - 443:443 volumes: - /data/nextcloud/nginx/vhost.d:/etc/nginx/vhost.d:rw - /data/nextcloud/nginx/html:/usr/share/nginx/html:rw - /data/nextcloud/nginx/certs:/etc/nginx/certs:ro - /etc/localtime:/etc/localtime:ro - /var/run/docker.sock:/tmp/docker.sock:ro restart: unless-stopped letsencrypt: image: jrcs/letsencrypt-nginx-proxy-companion:v1.12 container_name: nextcloud-letsencrypt depends_on: - nginx-proxy networks: - nextcloud_network volumes: - /data/nextcloud/nginx/vhost.d:/etc/nginx/vhost.d:rw - /data/nextcloud/nginx/html:/usr/share/nginx/html:rw - /data/nextcloud/nginx/certs:/etc/nginx/certs:rw - /etc/localtime:/etc/localtime:ro - /var/run/docker.sock:/var/run/docker.sock:ro restart: unless-stopped mysql: image: mariadb:10.4.10 container_name: nextcloud-mysql networks: - nextcloud_network volumes: - /data/nextcloud/mysql:/var/lib/mysql - /etc/localtime:/etc/localtime:ro environment: - MYSQL_ROOT_PASSWORD=mysql-root-p@ssw0rd - MYSQL_PASSWORD=nextcloud-p@ssw0rd - MYSQL_DATABASE=nextcloud - MYSQL_USER=nextcloud restart: unless-stopped nextcloud-app: image: nextcloud:17.0.1-apache container_name: nextcloud-app networks: - nextcloud_network depends_on: - letsencrypt - nginx-proxy - mysql volumes: - /data/nextcloud/app/html:/var/www/html - /data/nextcloud/app/config:/var/www/html/config - /data/nextcloud/app/custom_apps:/var/www/html/custom_apps - /data/nextcloud/app/data:/var/www/html/data - /data/nextcloud/app/themes:/var/www/html/themes - /etc/localtime:/etc/localtime:ro environment: - VIRTUAL_HOST=cloud.example.org.ua - LETSENCRYPT_HOST=cloud.example.org.ua - [email protected] restart: unless-stopped networks: nextcloud_network:
Обновляем образы:
[simterm]
root@setevoy-do-nextcloud-production:/opt/nextcloud# docker-compose -f nextcloud-compose.yml pull
[/simterm]
Пересоздаём стек:
[simterm]
root@setevoy-do-nextcloud-production:/opt/nextcloud# docker-compose -f nextcloud-compose.yml up --force-recreate
[/simterm]
Проверяем, что все файлы на месте.
systemd
Последним шагом — создаём systemd
unit-файл для сервиса, как описано в посте Linux: systemd сервис для Docker Compose, назовём его /etc/systemd/system/nextcloud.service
:
[Unit] Description=Nextcloud stack Requires=docker.service After=docker.service [Service] Restart=always WorkingDirectory=/opt/nextcloud ExecStart=/usr/local/bin/docker-compose -f nextcloud-compose.yml up ExecStop=/usr/local/bin/docker-compose -f nextcloud-compose.yml down [Install] WantedBy=multi-user.target
Запускаем сервис:
[simterm]
root@setevoy-do-nextcloud-production:~# systemctl start nextcloud root@setevoy-do-nextcloud-production:~# systemctl status nextcloud ● nextcloud.service - Nextcloud stack Loaded: loaded (/etc/systemd/system/nextcloud.service; disabled; vendor preset: enabled) Active: active (running) since Wed 2019-11-27 13:56:37 UTC; 4s ago Main PID: 16599 (docker-compose) Tasks: 7 (limit: 1167) Memory: 74.3M CGroup: /system.slice/nextcloud.service ├─16599 /usr/local/bin/docker-compose -f nextcloud-compose.yml up ...
[/simterm]
И добавляем в автозапуск:
[simterm]
root@setevoy-do-nextcloud-production:~# systemctl enable nextcloud Created symlink /etc/systemd/system/multi-user.target.wants/nextcloud.service → /etc/systemd/system/nextcloud.service.
[/simterm]
Готово.