Nextcloud: запуск в Docker Compose на Debian с SSL от Let’s Encrypt

Автор: | 27/11/2019

Недавно потестировал Nexcloud вообще, см. NextCloud: установка сервера на Debian с NGINX и PHP-FPM, и клиента на Arch Linux – в целом понравилось, работает – можно попробовать мигрировать с Dropbox на него.

Сегодня запустим Nextcloud полностью в Docker, на сервере с Debian 10 в Digital Ocean.

К серверу подключён отдельный диск, на котором будут все данные Nextcloud, что бы можно легко забекапить/перенести их.

Для запуска создадим Docker Compose стек, в котором будут:

  1. NGINX: проксирующий веб-сервер
  2. Lets Encrypt: клиент для генерации и обновления SSL-сертификатов
  3. MariaDB: сервер баз данных для хранения настроек Nextcloud
  4. 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]

Готово.