diff --git a/nextcloud/defaults/main.yml b/nextcloud/defaults/main.yml new file mode 100644 index 0000000..5b84253 --- /dev/null +++ b/nextcloud/defaults/main.yml @@ -0,0 +1,28 @@ +--- +nextcloud_version: 13.0.4 +nextcloud_dist_filename: 'nextcloud-{{ nextcloud_version }}.tar.bz2' +nextcloud_download_url: 'https://download.nextcloud.com/server/releases/{{ nextcloud_dist_filename }}' +nextcloud_use_redis: True +nextcloud_use_memcache: False +nextcloud_web_basedir: /var/www +nextcloud_web_root: '{{ nextcloud_web_basedir }}/nextcloud' +nextcloud_data_dir: /srv/nextcloud/data +nextcloud_oc_dir: /srv/nextcloud/oc_keys +nextcloud_servername: '{{ ansible_fqdn }}' +nextcloud_servernames: + - { webroot: '{{ nextcloud_web_root }}', id: 1, name: '{{ nextcloud_servername }}' } + +nextcloud_user: nextcloud + +nextcloud_db: pgsql +nextcloud_db_host: localhost +nextcloud_db_name: nextcloud +nextcloud_db_user: nextcloud_u +#nextcloud_db_pwd: 'Use a vault file' + +nextcloud_admin_user: nc_admin +#nextcloud_admin_u_pwd: 'Use a vault file' + +nextcloud_encryption_enabled: True +nextcloud_ldap_auth: False + diff --git a/nextcloud/meta/main.yml b/nextcloud/meta/main.yml new file mode 100644 index 0000000..5095747 --- /dev/null +++ b/nextcloud/meta/main.yml @@ -0,0 +1,6 @@ +--- +dependencies: + - { role: '../../library/roles/php-fpm' } + - { role: '../../library/roles/nginx' } + - { role: '../../library/roles/redis', when nextcloud_use_redis } + - { role: '../../library/roles/memcached', when nextcloud_use_memcache } diff --git a/nextcloud/tasks/main.yml b/nextcloud/tasks/main.yml new file mode 100644 index 0000000..53b6fe3 --- /dev/null +++ b/nextcloud/tasks/main.yml @@ -0,0 +1,3 @@ +--- +- import_tasks: nextcloud-nginx.yml +- import_tasks: nextcloud-install.yml diff --git a/nextcloud/tasks/nextcloud-install.yml b/nextcloud/tasks/nextcloud-install.yml new file mode 100644 index 0000000..84555a2 --- /dev/null +++ b/nextcloud/tasks/nextcloud-install.yml @@ -0,0 +1,83 @@ +--- +- block: + - name: Create the nextcloud webroot + file: dest={{ nextcloud_web_basedir }} owner=root group=root state=directory + + - name: Create the nextcloud data directory + file: dest={{ nextcloud_data_dir }} state=directory owner={{ item.user }} group={{ item.user }} + with_items: '{{ phpfpm_pools }}' + + - name: Get nextcloud + get_url: url={{ nextcloud_download_url }} dest=/srv/{{ nextcloud_dist_filename }} + + - name: Unpack the nextcloud archive + unarchive: remote_src=yes src=/srv/{{ nextcloud_dist_filename }} dest={{ item.doc_root }} owner={{ item.user }} group={{ item.user }} + args: + creates: '{{ item.doc_root }}/index.php' + with_items: '{{ phpfpm_pools }}' + + tags: [ 'nextcloud' ] + +- block: + - name: Configure the nextcloud instance + shell: cd {{ item.doc_root }} ; php occ maintenance:install --database="{{ nextcloud_db }}" --database-host "{{ nextcloud_db_host }}" --database-name "{{ nextcloud_db_name }}" --database-user "{{ nextcloud_db_user }}" --database-pass "{{ nextcloud_db_pwd }}" --admin-user "{{ nextcloud_admin_user }}" --admin-pass "{{ nextcloud_admin_u_pwd }}" --data-dir={{ nextcloud_data_dir }} ; touch {{ nextcloud_data_dir }}/.ht_nextcloud_setup + args: + creates: '{{ nextcloud_data_dir }}/.ht_nextcloud_setup' + with_items: '{{ phpfpm_pools }}' + + - name: Set the trusted domains list + shell: cd {{ item.webroot }} ; php occ config:system:set trusted_domains {{ item.id }} --value={{ item.name }} ; touch {{ nextcloud_data_dir }}/.ht_nextcloud_trusted_domains + args: + creates: '{{ nextcloud_data_dir }}/.ht_nextcloud_trusted_domains' + with_items: '{{ nextcloud_servernames }}' + + - name: Setup the cron configuration + shell: cd {{ item.webroot }} ; php occ background:cron ; touch {{ nextcloud_data_dir }}/.ht_nextcloud_cron + args: + creates: 'touch {{ nextcloud_data_dir }}/.ht_nextcloud_cron' + with_items: '{{ nextcloud_servernames }}' + tags: [ 'nextcloud', 'nextcloud_config_cron' ] + + - name: Install the nextcloud cron job + cron: user={{ item.user }} minute="*/15" job="php -f {{ item.doc_root }}/cron.php" name="NextCloud cron job" + with_items: '{{ phpfpm_pools }}' + tags: [ 'nextcloud', 'nextcloud_config_cron' ] + + become: True + become_user: '{{ nextcloud_user }}' + tags: [ 'nextcloud', 'nextcloud_config' ] + +- block: + - name: Create the nextcloud encryption keys directory + become_user: root + file: dest={{ nextcloud_oc_dir }} state=directory owner={{ item.user }} group={{ item.user }} + with_items: '{{ phpfpm_pools }}' + + - name: Activate global encryption + shell: cd {{ item.doc_root }} ; php occ app:enable encryption ; php occ encryption:enable ; php occ encryption:enable-master-key ; php occ encryption:change-key-storage-root {{ nextcloud_oc_dir }} ; touch {{ nextcloud_oc_dir }}/.ht_nextcloud_oc + args: + creates: '{{ nextcloud_oc_dir }}/.ht_nextcloud_oc' + with_items: '{{ phpfpm_pools }}' + + become: True + become_user: '{{ nextcloud_user }}' + when: nextcloud_encryption_enabled + tags: [ 'nextcloud', 'nextcloud_config', 'nextcloud_config_oc' ] + +- block: + - name: Enable ldap + shell: cd {{ item.doc_root }} ; php occ app:enable user_ldap ; touch {{ item.doc_root }}/.ht_nextcloud_ldap_enabled + args: + creates: '{{ item.doc_root }}/.ht_nextcloud_ldap_enabled' + with_items: '{{ phpfpm_pools }}' + + - name: Configure ldap + shell: cd {{ item.doc_root }} ; php occ ldap:create-empty-config ; touch {{ item.doc_root }}/.ht_nextcloud_ldap_configured + args: + creates: '{{ item.doc_root }}/.ht_nextcloud_ldap_configured' + with_items: '{{ phpfpm_pools }}' + + become: True + become_user: '{{ nextcloud_user }}' + when: nextcloud_ldap_auth + tags: [ 'nextcloud', 'nextcloud_config', 'nextcloud_config_ldap' ] diff --git a/nextcloud/tasks/nextcloud-nginx.yml b/nextcloud/tasks/nextcloud-nginx.yml new file mode 100644 index 0000000..4c43aa9 --- /dev/null +++ b/nextcloud/tasks/nextcloud-nginx.yml @@ -0,0 +1,17 @@ +--- +- block: + - name: Install the nginx virtualhosts + template: src=nginx-virthost.conf dest=/etc/nginx/sites-available/{{ item.virthost }} owner=root group=root mode=0444 + with_items: '{{ phpfpm_pools }}' + notify: Reload nginx + + - name: Enable the nginx virtualhosts + file: src=/etc/nginx/sites-available/{{ item.virthost }} dest=/etc/nginx/sites-enabled/{{ item.virthost }} state=link + with_items: '{{ phpfpm_pools }}' + notify: Reload nginx + + - name: Create the nginx body temp directory + file: dest={{ nginx_client_body_temp_dir }} state=directory owner=www-data group=www-data mode=1700 + when: nginx_client_body_temp_dir is defined + + tags: [ 'nginx', 'virtualhost', 'nextcloud' ] diff --git a/nextcloud/templates/nginx-virthost.conf b/nextcloud/templates/nginx-virthost.conf new file mode 100644 index 0000000..292e319 --- /dev/null +++ b/nextcloud/templates/nginx-virthost.conf @@ -0,0 +1,158 @@ +upstream php-handler { + server {{ item.listen }}; + #server unix:/var/run/php5-fpm.sock; +} + +server { + listen 80; + listen [::]:80; + server_name {{ item.nginx_servername }}; + # enforce https + location ~ /\.(?!well-known).* { + deny all; + access_log off; + log_not_found off; + return 404; + } + include /etc/nginx/snippets/letsencrypt-proxy.conf; + location / { + return 301 https://$server_name$request_uri; + } +} + +server { + listen 443 ssl http2; + listen [::]:443 ssl http2; + server_name {{ item.nginx_servername }}; + + include /etc/nginx/snippets/nginx-server-ssl.conf; + server_tokens off; + + # Add headers to serve security related headers + # Before enabling Strict-Transport-Security headers please read into this + # topic first. + # add_header Strict-Transport-Security "max-age=15768000; + # includeSubDomains; preload;"; + # + # WARNING: Only add the preload option once you read about + # the consequences in https://hstspreload.org/. This option + # will add the domain to a hardcoded list that is shipped + # in all major browsers and getting removed from this list + # could take several months. + add_header X-Content-Type-Options nosniff; + add_header X-XSS-Protection "1; mode=block"; + add_header X-Robots-Tag none; + add_header X-Download-Options noopen; + add_header X-Permitted-Cross-Domain-Policies none; + + location ~ /\.(?!well-known).* { + deny all; + access_log off; + log_not_found off; + return 404; + } + + # Path to the root of your installation + root {{ item.doc_root }}; + + location = /robots.txt { + allow all; + log_not_found off; + access_log off; + } + + location = /favicon.ico { + log_not_found off; + access_log off; + } + # The following 2 rules are only needed for the user_webfinger app. + # Uncomment it if you're planning to use this app. + #rewrite ^/.well-known/host-meta /public.php?service=host-meta last; + #rewrite ^/.well-known/host-meta.json /public.php?service=host-meta-json + # last; + + location = /.well-known/carddav { + return 301 $scheme://$host/remote.php/dav; + } + location = /.well-known/caldav { + return 301 $scheme://$host/remote.php/dav; + } + + # set max upload size + client_max_body_size 512M; + fastcgi_buffers 64 4K; + + # Enable gzip but do not remove ETag headers + 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; + + # Uncomment if your server is build with the ngx_pagespeed module + # This module is currently not supported. + #pagespeed off; + + location / { + rewrite ^ /index.php$uri; + } + + 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/.+|ocs-provider/.+)\.php(?:$|/) { + fastcgi_split_path_info ^(.+\.php)(/.*)$; + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_param PATH_INFO $fastcgi_path_info; + fastcgi_param HTTPS on; + #Avoid sending the security headers twice + fastcgi_param modHeadersAvailable true; + fastcgi_param front_controller_active true; + fastcgi_pass php-handler; + fastcgi_intercept_errors on; + fastcgi_request_buffering off; + } + + location ~ ^/(?:updater|ocs-provider)(?:$|/) { + try_files $uri/ =404; + index index.php; + } + + # Adding the cache control header for js and css files + # Make sure it is BELOW the PHP block + location ~ \.(?:css|js|woff|svg|gif)$ { + try_files $uri /index.php$uri$is_args$args; + add_header Cache-Control "public, max-age=15778463"; + # Add headers to serve security related headers (It is intended to + # have those duplicated to the ones above) + # Before enabling Strict-Transport-Security headers please read into + # this topic first. + # add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;"; + # + # WARNING: Only add the preload option once you read about + # the consequences in https://hstspreload.org/. This option + # will add the domain to a hardcoded list that is shipped + # in all major browsers and getting removed from this list + # could take several months. + add_header X-Content-Type-Options nosniff; + add_header X-XSS-Protection "1; mode=block"; + add_header X-Robots-Tag none; + add_header X-Download-Options noopen; + add_header X-Permitted-Cross-Domain-Policies none; + # Optional: Don't log access to assets + access_log off; + } + + location ~ \.(?:png|html|ttf|ico|jpg|jpeg)$ { + try_files $uri /index.php$uri$is_args$args; + # Optional: Don't log access to other assets + access_log off; + } +} + diff --git a/nextcloud/vars/main.yml b/nextcloud/vars/main.yml new file mode 100644 index 0000000..e21f911 --- /dev/null +++ b/nextcloud/vars/main.yml @@ -0,0 +1,54 @@ +--- +nginx_use_common_virthost: False +phpfpm_default_user: '{{ nextcloud_user }}' +phpfpm_default_pool_name: nextcloud +redis_install: True +http_port: 80 +https_port: 443 + +php_version: 7.0 +phpfpm_base_dir: '/etc/php/{{ php_version }}/fpm' +phpfpm_cli_dir: '/etc/php/{{ php_version }}/cli' + +php_fpm_packages: + - 'php{{ php_version }}-fpm' + - 'php{{ php_version }}-gd' + - 'php{{ php_version }}-json' + - 'php{{ php_version }}-ldap' + - 'php{{ php_version }}-{{ nextcloud_db }}' + - 'php{{ php_version }}-mcrypt' + - 'php{{ php_version }}-xml' + - 'php{{ php_version }}-mbstring' + - 'php{{ php_version }}-intl' + - 'php{{ php_version }}-curl' + - 'php{{ php_version }}-zip' + - 'php{{ php_version }}-bz2' + - 'php{{ php_version }}-gmp' + - 'php-imagick' + - 'php-redis' + - 'php-apcu' + +phpfpm_default_memory_limit: "384M" + +php_global_settings: + - { option: 'always_populate_raw_post_data', value: '-1' } + - { option: 'allow_url_fopen', value: 'off' } + - { option: 'max_execution_time', value: '240' } + - { option: 'memory_limit', value: '{{ phpfpm_default_memory_limit }}' } + - { option: 'max_input_vars', value: '1400' } + - { option: 'post_max_size', value: '32M' } + - { option: 'upload_max_filesize', value: '32M' } + - { option: 'opcache.enable', value: '1' } + - { option: 'opcache.enable_cli', value: '1' } + - { option: 'opcache.interned_strings_buffer', value: '8' } + - { option: 'opcache.max_accelerated_files', value: '10000' } + - { option: 'opcache.memory_consumption', value: '128' } + - { option: 'opcache.save_comments', value: '1' } + - { option: 'opcache.revalidate_freq', value: '1' } + +php_cli_global_settings: '{{ php_global_settings }}' + + +phpfpm_pools: + - { pool_name: '{{ phpfpm_default_pool_name }}', app_context: '{{ phpfpm_default_context }}', user: '{{ phpfpm_default_user }}', group: '{{ phpfpm_default_group }}', listen: '{{ phpfpm_default_listen }}', allowed_clients: '{{ phpfpm_default_allowed_clients }}', pm: '{{ phpfpm_default_pm }}', pm_max_children: '{{ phpfpm_default_pm_max_children }}', pm_start_servers: '{{ phpfpm_default_pm_start_servers }}', pm_min_spare: '{{ phpfpm_default_pm_min_spare_servers }}', pm_max_spare: '{{ phpfpm_default_pm_max_spare_servers }}', pm_max_requests: '{{ phpfpm_default_pm_max_requests }}', pm_status_enabled: '{{ phpfpm_default_pm_status_enabled }}', pm_status_path: '{{ phpfpm_default_pm_status_path }}', ping_enabled: '{{ phpfpm_default_ping_enabled }}', ping_path: '{{ phpfpm_default_ping_path }}', ping_response: '{{ phpfpm_default_ping_response }}', display_errors: '{{ phpfpm_default_display_errors }}', log_errors: '{{ phpfpm_default_log_errors }}', memory_limit: '{{ phpfpm_default_memory_limit }}', slowlog_timeout: '{{ phpfpm_default_slowlog_timeout }}', rlimit_files: '{{ phpfpm_default_rlimit_files }}', php_extensions: '{{ phpfpm_default_extensions }}', define_custom_variables: '{{ phpfpm_default_define_custom_variables }}', doc_root: '{{ nextcloud_web_root }}', req_term_timeout: '240s', virthost: '{{ nextcloud_servername }}', nginx_servername: '{{ nextcloud_servername }}' } +