Getting started

Database setup

It is recommended that you install a database server. You can install one on the same host as ownCloud or choose a different host:

[debops_service_mariadb_server]
hostname

In case you chose a different host, you will need to specify which of your database servers the ownCloud instance should use by specifying the database server host as owncloud__database_server.

If you are upgrading an existing Nextcloud installation, you should follow Enabling MySQL 4-byte support and then set the following in your inventory of the database server:

mariadb_server__options:
  - section: 'mysqld'
    options:

      ## https://docs.nextcloud.com/server/16/admin_manual/configuration_database/mysql_4byte_support.html
      'innodb_large_prefix': 'on'
      'innodb_file_format': 'barracuda'
      'innodb_file_per_table': 'true'

For database clean installs this is not required anymore because MySQL 4-byte is enabled by default by the debops.mariadb_server Ansible role.

In memory caching

Nextcloud and ownCloud recommend to setup Redis for caching. You can install a Redis server on the same host as ownCloud or choose a different host:

[debops_service_redis_server]
hostname

This role will use a Redis server automatically when it is managed by debops.redis_server Ansible role.

In case you chose a different host, you will need to specify which of your Redis servers the ownCloud instance should use by setting the Redis server host as owncloud__redis_host and setting owncloud__redis_enabled to True. Additionally, you will need to set the owncloud__redis_password. Refer to debops.redis_server documentation for details.

PHP configuration

Starting with Nextcloud 16, a setup warning is emitted in the Nextcloud admin web interface "The PHP memory limit is below the recommended value of 512MB.". The role already configures Nginx to pass an increased memory_limit to PHP. However, this might not be picked up in some cases. When this happens you might want to set the following in your inventory:

php__ini_memory_limit: '512M'

Choosing a Webserver

Supported webservers:

This role started out using Nginx as Webserver. However, ownCloud don’t officially support Nginx. Support for the Apache HTTP Server has been added to the role using debops.apache as role dependency. NextCloud lists Nginx as supported but still recommends Apache.

The current default Webserver is Nginx. Because despite the fact that only Apache is officially supported/recommended, Nginx has been successfully used with this role for some time now. If you have trouble then this would be a good time to try to run it with Apache.

The ownCloud System Requirements don’t use PHP-FPM in their default configuration. You can set the following in your inventory to not install FPM on the ownCloud host:

php__server_api_packages:
  - 'cli'

Switching Webservers

Assuming you where using one Webserver before on a host but want to switch then follow the steps in Choosing a Webserver and additionally add the host to the debops_service_${not_chosen_webserver} group of the opposite webserver you chose for ownCloud. Now add this:

${not_chosen_webserver}__deploy_state: 'absent'

to your inventory.

Note: Replace the ${not_chosen_webserver} placeholders.

Then run the site playbook or just the playbook of the unwanted webserver followed by the debops.owncloud playbook. This will render ${not_chosen_webserver} the unwanted webserver harmless and setup the chosen webserver.

Upgrade

All upgrades be it major or patch need to be done manually for now. The role does not automate this. The way to support Nextcloud auto upgrades would be to use the Nextcloud Docker image because it includes an application upgrade script. The role could be extended to support using the Docker image if needed.

Upgrade the application using the built-in upgrade feature, then rerun the service playbook for this role to ensure the matching settings are applied.

If the application complains under /settings/admin/overview then you might need to run:

occ upgrade; occ db:add-missing-indice; occ db:add-missing-columns; occ db:convert-filecache-bigint; occ db:add-missing-primary-keys && occ maintenance:mode --off

It also does not hurt to run that by default.

Expected warnings

Nextcloud and ownCloud have a self check under "Administration" -> "Overview". Some warnings are expected to be shown.

  • Nextcloud 21 and newer: Module php-imagick in this instance has no SVG support. For better compatibility it is recommended to install it.

    Background: SVG support is disabled for security reasons by default. Lets keep it at that for now until we can better assess the situation.

Example inventory

To setup ownCloud on a given host it should be included in the [debops_service_owncloud] Ansible inventory group:

[debops_service_owncloud]
hostname

Note that the debops_service_owncloud group uses the default webserver, refer to Choosing a Webserver.

Ansible facts

The role gathers various Ansible facts about ownCloud for internal use or use by other roles or playbooks.

One of the sources for the facts is the /var/www/owncloud/config/config.php file which has 0640 as default permissions. The remote user who gathers the facts should be able to read this file. Note that facts gathering does not happen with elevated privileges by default. One way to achieve this is by making your configuration management user member of the www-data group by including the following in your inventory:

bootstrap__admin_groups: [ 'admins', 'staff', 'adm', 'sudo', 'www-data' ]

The following Ansible facts are available:

{
    "auto_security_updates_enabled": false,
    "datadirectory": "/var/www/owncloud/data",
    "enabled": true,
    "instanceid": "xxxxxxxxxxxx",
    "maintenance": false,
    "release": "9.0",
    "theme": "debops",
    "trusted_domains": [
        "cloud.example.org"
    ],
    "updatechecker": false,
    "variant": "owncloud",
    "version": "9.0.7.1",
    "webserver": "nginx"
}

Note that the role uses Ansible facts gathered from the config.php file internally and might not work as expected when those facts can not be gathered.

The following can happen when the configuration management user has no access to the config.php file:

  • Certain occ commands are not available in maintenance mode. The role normally filters those commands out if it detects that ownCloud is in maintenance mode. Maintenance mode is assumed to be off if it can not be detected. If it is on, role execution will stop when one of those occ commands is encountered.

and only the following facts will be available in this case:

{
    "auto_security_updates_enabled": true,
    "enabled": true,
    "variant": "owncloud",
    "webserver": "nginx"
}

Example playbook

The following playbooks are used in DebOps. If you are using these role without DebOps you might need to adapt them to make them work in your setup.

Ansible playbook that uses the debops.owncloud role together with debops.nginx:

---

- name: Install and manage ownCloud instances with Nginx as webserver
  collections: [ 'debops.debops', 'debops.roles01',
                 'debops.roles02', 'debops.roles03' ]
  hosts: [ 'debops_service_owncloud', 'debops_service_owncloud_nginx' ]
  become: True

  environment: '{{ inventory__environment | d({})
                   | combine(inventory__group_environment | d({}))
                   | combine(inventory__host_environment  | d({})) }}'

  pre_tasks:

    - name: Apply keyring configuration for php environment
      ansible.builtin.import_role:
        name: 'keyring'
      vars:
        keyring__dependent_apt_keys:
          - '{{ php__keyring__dependent_apt_keys }}'
          - '{{ mariadb__keyring__dependent_apt_keys if (owncloud__database == "mariadb") else [] }}'
          - '{{ postgresql__keyring__dependent_apt_keys if (owncloud__database == "postgresql") else [] }}'
          - '{{ nginx__keyring__dependent_apt_keys }}'
          - '{{ owncloud__keyring__dependent_apt_keys }}'
        keyring__dependent_gpg_keys:
          - '{{ owncloud__keyring__dependent_gpg_keys }}'
      tags: [ 'role::keyring', 'skip::keyring', 'role::php',
              'role::mariadb', 'role::postgresql',
              'role::nginx', 'role::owncloud' ]

    - name: Prepare php environment
      ansible.builtin.import_role:
        name: 'php'
        tasks_from: 'main_env'
      tags: [ 'role::php', 'role::php:env', 'role::logrotate' ]

    - name: Prepare owncloud environment
      ansible.builtin.import_role:
        name: 'owncloud'
        tasks_from: 'main_env'
      tags: [ 'role::owncloud', 'role::owncloud:env', 'role::nginx' ]

  roles:

    - role: apt_preferences
      tags: [ 'role::apt_preferences', 'skip::apt_preferences', 'role::nginx', 'role::php' ]
      apt_preferences__dependent_list:
        - '{{ nginx__apt_preferences__dependent_list }}'
        - '{{ owncloud__apt_preferences__dependent_list }}'
        - '{{ php__apt_preferences__dependent_list }}'

    - role: ferm
      tags: [ 'role::ferm', 'skip::ferm', 'role::nginx' ]
      ferm__dependent_rules:
        - '{{ nginx__ferm__dependent_rules }}'

    - role: python
      tags: [ 'role::python', 'skip::python', 'role::ldap', 'role::mariadb', 'role::postgresql' ]
      python__dependent_packages3:
        - '{{ ldap__python__dependent_packages3 }}'
        - '{{ mariadb__python__dependent_packages3
              if (owncloud__database == "mariadb")
              else [] }}'
        - '{{ postgresql__python__dependent_packages3
              if (owncloud__database == "postgresql")
              else [] }}'
        - '{{ nginx__python__dependent_packages3 }}'
      python__dependent_packages2:
        - '{{ ldap__python__dependent_packages2 }}'
        - '{{ mariadb__python__dependent_packages2
              if (owncloud__database == "mariadb")
              else [] }}'
        - '{{ postgresql__python__dependent_packages2
              if (owncloud__database == "postgresql")
              else [] }}'
        - '{{ nginx__python__dependent_packages2 }}'

    - role: ldap
      tags: [ 'role::ldap', 'skip::ldap' ]
      ldap__dependent_tasks:
        - '{{ owncloud__ldap__dependent_tasks }}'

    - role: mariadb
      tags: [ 'role::mariadb', 'skip::mariadb' ]
      mariadb__dependent_databases: '{{ owncloud__mariadb__dependent_databases }}'
      mariadb__dependent_users: '{{ owncloud__mariadb__dependent_users }}'
      when: (owncloud__database == 'mariadb')

    - role: postgresql
      tags: [ 'role::postgresql', 'skip::postgresql' ]
      postgresql__dependent_roles: '{{ owncloud__postgresql__dependent_roles }}'
      postgresql__dependent_groups: '{{ owncloud__postgresql__dependent_groups }}'
      postgresql__dependent_databases: '{{ owncloud__postgresql__dependent_databases }}'
      when: (owncloud__database == 'postgresql')

    - role: unattended_upgrades
      tags: [ 'role::unattended_upgrades', 'skip::unattended_upgrades' ]
      unattended_upgrades__dependent_origins: '{{ owncloud__unattended_upgrades__dependent_origins }}'

    - role: php
      tags: [ 'role::php', 'skip::php' ]
      php__dependent_packages:
        - '{{ owncloud__php__dependent_packages }}'
      php__dependent_configuration:
        - '{{ owncloud__php__dependent_configuration }}'
      php__dependent_pools:
        - '{{ owncloud__php__dependent_pools }}'

    - role: cron
      tags: [ 'role::cron', 'skip::cron' ]

    - role: logrotate
      tags: [ 'role::logrotate', 'skip::logrotate' ]
      logrotate__dependent_config:
        - '{{ php__logrotate__dependent_config }}'
        - '{{ owncloud__logrotate__dependent_config }}'

    - role: nginx
      tags: [ 'role::nginx', 'skip::nginx' ]
      nginx__dependent_maps:
        - '{{ owncloud__nginx__dependent_maps }}'
      nginx__dependent_servers:
        - '{{ owncloud__nginx__dependent_servers }}'
      nginx__dependent_upstreams:
        - '{{ owncloud__nginx__dependent_upstreams }}'

    - role: owncloud
      tags: [ 'role::owncloud', 'skip::owncloud' ]

Ansible playbook that uses the debops.owncloud role together with debops.apache:

---

- name: Install and manage ownCloud instances with Apache as webserver
  collections: [ 'debops.debops', 'debops.roles01',
                 'debops.roles02', 'debops.roles03' ]
  hosts: [ 'debops_service_owncloud_apache' ]
  become: True

  environment: '{{ inventory__environment | d({})
                   | combine(inventory__group_environment | d({}))
                   | combine(inventory__host_environment  | d({})) }}'

  pre_tasks:

    - name: Apply keyring configuration for php environment
      ansible.builtin.import_role:
        name: 'keyring'
      vars:
        keyring__dependent_apt_keys:
          - '{{ php__keyring__dependent_apt_keys }}'
          - '{{ mariadb__keyring__dependent_apt_keys if (owncloud__database == "mariadb") else [] }}'
          - '{{ postgresql__keyring__dependent_apt_keys if (owncloud__database == "postgresql") else [] }}'
          - '{{ owncloud__keyring__dependent_apt_keys }}'
        keyring__dependent_gpg_keys:
          - '{{ owncloud__keyring__dependent_gpg_keys }}'
      tags: [ 'role::keyring', 'skip::keyring', 'role::php',
              'role::mariadb', 'role::postgresql', 'role::owncloud' ]

    - name: Prepare php environment
      ansible.builtin.import_role:
        name: 'php'
        tasks_from: 'main_env'
      tags: [ 'role::php', 'role::php:env', 'role::logrotate' ]

    - name: Prepare apache environment
      ansible.builtin.import_role:
        name: 'apache'
        tasks_from: 'main_env'
      tags: [ 'role::apache', 'role::apache:env' ]

    - name: Prepare owncloud environment
      ansible.builtin.import_role:
        name: 'owncloud'
        tasks_from: 'main_env'
      tags: [ 'role::owncloud', 'role::owncloud:env' ]

  roles:

    - role: apt_preferences
      tags: [ 'role::apt_preferences', 'skip::apt_preferences' ]
      apt_preferences__dependent_list:
        - '{{ owncloud__apt_preferences__dependent_list }}'
        - '{{ php__apt_preferences__dependent_list }}'

    - role: ferm
      tags: [ 'role::ferm', 'skip::ferm' ]
      ferm__dependent_rules:
        - '{{ apache__ferm__dependent_rules }}'

    - role: python
      tags: [ 'role::python', 'skip::python', 'role::ldap', 'role::mariadb', 'role::postgresql' ]
      python__dependent_packages3:
        - '{{ ldap__python__dependent_packages3 }}'
        - '{{ mariadb__python__dependent_packages3
              if (owncloud__database == "mariadb")
              else [] }}'
        - '{{ postgresql__python__dependent_packages3
              if (owncloud__database == "postgresql")
              else [] }}'
      python__dependent_packages2:
        - '{{ ldap__python__dependent_packages2 }}'
        - '{{ mariadb__python__dependent_packages2
              if (owncloud__database == "mariadb")
              else [] }}'
        - '{{ postgresql__python__dependent_packages2
              if (owncloud__database == "postgresql")
              else [] }}'

    - role: ldap
      tags: [ 'role::ldap', 'skip::ldap' ]
      ldap__dependent_tasks:
        - '{{ owncloud__ldap__dependent_tasks }}'

    - role: mariadb
      tags: [ 'role::mariadb', 'skip::mariadb' ]
      mariadb__dependent_users: '{{ owncloud__mariadb__dependent_users }}'
      when: (owncloud__database == 'mariadb')

    - role: postgresql
      tags: [ 'role::postgresql', 'skip::postgresql' ]
      postgresql__dependent_roles: '{{ owncloud__postgresql__dependent_roles }}'
      postgresql__dependent_groups: '{{ owncloud__postgresql__dependent_groups }}'
      postgresql__dependent_databases: '{{ owncloud__postgresql__dependent_databases }}'
      when: (owncloud__database == 'postgresql')

    - role: unattended_upgrades
      tags: [ 'role::unattended_upgrades', 'skip::unattended_upgrades' ]
      unattended_upgrades__dependent_origins: '{{ owncloud__unattended_upgrades__dependent_origins }}'

    - role: php
      tags: [ 'role::php', 'skip::php' ]
      php__dependent_packages:
        - '{{ owncloud__php__dependent_packages }}'
      php__dependent_configuration:
        - '{{ owncloud__php__dependent_configuration }}'
      php__dependent_pools:
        - '{{ owncloud__php__dependent_pools }}'

    - role: cron
      tags: [ 'role::cron', 'skip::cron' ]

    - role: logrotate
      tags: [ 'role::logrotate', 'skip::logrotate' ]
      logrotate__dependent_config:
        - '{{ php__logrotate__dependent_config }}'
        - '{{ owncloud__logrotate__dependent_config }}'

    - role: apache
      tags: [ 'role::apache', 'skip::apache' ]
      apache__dependent_snippets: '{{ owncloud__apache__dependent_snippets }}'
      apache__dependent_vhosts:
        - '{{ owncloud__apache__dependent_vhosts }}'

    - role: owncloud
      tags: [ 'role::owncloud', 'skip::owncloud' ]

These playbooks are shipped with DebOps and are also contained in this role under docs/playbooks/.

Ansible tags

You can use Ansible --tags or --skip-tags parameters to limit what tasks are performed during Ansible run. This can be used after a host was first configured to speed up playbook execution, when you are sure that most of the configuration is already in the desired state.

Available role tags:

role::owncloud

Main role tag, should be used in the playbook to execute all of the role tasks as well as role dependencies.

role::owncloud:pkg

Tasks related to system package management like installing, upgrading or removing packages.

role::owncloud:tarball

Tasks related to installing by Tarball.

role::owncloud:config

Run tasks related to ownCloud configuration and setup.

role::owncloud:mail

Run tasks related to the deployment of the mail configuration.

role::owncloud:occ

Run tasks related to the occ command.

role::owncloud:occ_config

Run tasks related to occ config: commands generated from owncloud__apps_config variables.

role::owncloud:auto_upgrade

Run tasks related preparing ownCloud auto upgrade.

role::owncloud:ldap

Run tasks related to the LDAP configuration.

role::owncloud:theme

Run tasks related to the configuring the ownCloud theme.

role::owncloud:copy

Run tasks related to copying and deletion of files in user profiles.