diff --git a/resources/docker-compose/nextcloud.yaml.j2 b/resources/docker-compose/nextcloud.yaml.j2 index 0934058..c52d6f7 100644 --- a/resources/docker-compose/nextcloud.yaml.j2 +++ b/resources/docker-compose/nextcloud.yaml.j2 @@ -2,6 +2,21 @@ version: "{{ omni_compose_version | string }}" +x-server-env: &server-env + NEXTCLOUD_DATA_DIR: /data/ + NEXTCLOUD_ADMIN_USER: admin + NEXTCLOUD_ADMIN_PASSWORD: {{ omni_compose_app_secrets.nextcloud.admin_password }} + NEXTCLOUD_TRUSTED_DOMAINS: localhost {{ inventory_hostname }} {{ omni_compose_apps.nextcloud.published.host }} + MYSQL_DATABASE: nextcloud + MYSQL_USER: root + MYSQL_PASSWORD: {{ omni_compose_app_secrets.nextcloud.database_password }} + MYSQL_HOST: database + REDIS_HOST: cache + PHP_MEMORY_LIMIT: "12G" + PHP_UPLOAD_LIMIT: "6G" + PHP_INI_SCAN_DIR: /usr/local/etc/php/conf.d:/var/www/html/ + + networks: nextcloud: name: nextcloud @@ -38,6 +53,10 @@ services: source: database target: /var/lib/mysql read_only: false + - type: volume + source: proxy + target: /etc/mysql/conf.d + read_only: true environment: MYSQL_ROOT_PASSWORD: {{ omni_compose_app_secrets.nextcloud.database_password }} MYSQL_DATABASE: nextcloud @@ -94,17 +113,32 @@ services: source: config target: /var/www/html read_only: false - environment: - NEXTCLOUD_DATA_DIR: /data/ - NEXTCLOUD_ADMIN_USER: admin - NEXTCLOUD_ADMIN_PASSWORD: {{ omni_compose_app_secrets.nextcloud.admin_password }} - NEXTCLOUD_TRUSTED_DOMAINS: localhost {{ inventory_hostname }} {{ omni_compose_apps.nextcloud.published.host }} - MYSQL_DATABASE: nextcloud - MYSQL_USER: root - MYSQL_PASSWORD: {{ omni_compose_app_secrets.nextcloud.database_password }} - MYSQL_HOST: database - REDIS_HOST: cache - PHP_MEMORY_LIMIT: "4G" - PHP_UPLOAD_LIMIT: "4G" + environment: *server-env deploy: replicas: 1 + + cron: + image: nextcloud:{{ omni_compose_apps.nextcloud.versions.server | default(omni_compose_apps.nextcloud.versions.default) }} + command: php /var/www/html/cron.php + hostname: nextcloud-cron + user: "{{ omni_compose_apps.nextcloud.account.uid }}" + networks: + - nextcloud + depends_on: + - database + - cache + volumes: + - type: volume + source: data + target: /data + read_only: false + - type: volume + source: config + target: /var/www/html + read_only: false + environment: *server-env + deploy: + replicas: 1 + restart_policy: + condition: any + delay: "4m" diff --git a/resources/nextcloud-mariadb.cnf b/resources/nextcloud-mariadb.cnf new file mode 100644 index 0000000..e566a44 --- /dev/null +++ b/resources/nextcloud-mariadb.cnf @@ -0,0 +1,9 @@ +# https://docs.nextcloud.com/server/21/admin_manual/installation/server_tuning.html#using-mariadb-mysql-instead-of-sqlite +# https://github.com/owncloud/core/issues/20967#issuecomment-205474772 +[mysqld] +innodb_buffer_pool_size = 1G +innodb_buffer_pool_instance = 1 +innodb_flush_log_at_trx_commit = 2 +innodb_log_buffer_size = 32M +innodb_max_dirty_pages_pct = 90 +innodb_io_capacity=4000 diff --git a/resources/nextcloud-php-fpm.ini b/resources/nextcloud-php-fpm.ini new file mode 100644 index 0000000..5b63765 --- /dev/null +++ b/resources/nextcloud-php-fpm.ini @@ -0,0 +1,15 @@ +; https://docs.nextcloud.com/server/21/admin_manual/installation/server_tuning.html#tune-php-fpm +pm = dynamic +pm.max_children = 120 +pm.start_servers = 12 +pm.min_spare_servers = 6 +pm.max_spare_servers = 18 + +; https://github.com/phpredis/phpredis#php-session-handler +session.save_handler = redis +session.save_path = "tcp://cache:6379?weight=1" + +; https://docs.nextcloud.com/server/21/admin_manual/configuration_server/caching_configuration.html#id2 +redis.session.locking_enabled=1 +redis.session.lock_retries=-1 +redis.session.lock_wait_time=10000 diff --git a/resources/nginx/nextcloud-proxy.conf b/resources/nginx/nextcloud-proxy.conf index 02f8568..1671632 100644 --- a/resources/nginx/nextcloud-proxy.conf +++ b/resources/nginx/nextcloud-proxy.conf @@ -1,50 +1,88 @@ server { listen 80; root /usr/share/nginx/nextcloud; - index index.php index.html index.htm; + index index.php index.html index.htm /index.php$request_uri; - location / { + client_max_body_size 4G; + fastcgi_buffers 64 4k; + + 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; + + add_header Referrer-Policy "no-referrer" always; + add_header X-Content-Type-Options "nosniff" always; + add_header X-Download-Options "noopen" always; + add_header X-Frame-Options "SAMEORIGIN" always; + add_header X-Permitted-Cross-Domain-Policies "none" always; + add_header X-Robots-Tag "none" always; + add_header X-XSS-Protection "1; mode=block" always; + + # Remove X-Powered-By, which is an information leak + fastcgi_hide_header X-Powered-By; + + location = / { + if ( $http_user_agent ~ ^DavClnt ) { + return 302 /remote.php/webdav/$is_args$args; + } + } + + location = /robots.txt { + allow all; + log_not_found off; + access_log off; + } + + location ^~ /.well-known { + location = /.well-known/carddav { return 301 /remote.php/dav/; } + location = /.well-known/caldav { return 301 /remote.php/dav/; } + location ^~ /.well-known { return 301 /index.php$uri; } try_files $uri $uri/ =404; } + location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)(?:$|/) { return 404; } + location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console) { return 404; } + location ~ [^/]\.php(/|$) { fastcgi_split_path_info ^(.+?\.php)(/.*)$; - if (!-f $document_root$fastcgi_script_name) { - return 404; - } + set $path_info $fastcgi_path_info; + try_files $fastcgi_script_name =404; + + include fastcgi_params; + fastcgi_intercept_errors on; + fastcgi_request_buffering off; + + fastcgi_param SCRIPT_FILENAME /var/www/html/$fastcgi_script_name; + fastcgi_param PATH_INFO $path_info; + fastcgi_param DOCUMENT_ROOT /var/www/html/; + fastcgi_param modHeadersAvailable true; + fastcgi_param front_controller_active true; + fastcgi_param HTTPS $https; + fastcgi_param REDIRECT_STATUS 200; # Mitigate https://httpoxy.org/ vulnerabilities - fastcgi_param HTTP_PROXY ""; + fastcgi_param HTTP_PROXY ""; fastcgi_pass server:9000; - fastcgi_index index.php; + } - fastcgi_param QUERY_STRING $query_string; - fastcgi_param REQUEST_METHOD $request_method; - fastcgi_param CONTENT_TYPE $content_type; - fastcgi_param CONTENT_LENGTH $content_length; + location ~ \.(?:css|js|svg|gif)$ { + try_files $uri /index.php$request_uri; + expires 6M; + access_log off; + } - fastcgi_param SCRIPT_FILENAME /var/www/html$fastcgi_script_name; - fastcgi_param SCRIPT_NAME $fastcgi_script_name; - fastcgi_param PATH_INFO $fastcgi_path_info; - fastcgi_param PATH_TRANSLATED /var/www/html$fastcgi_path_info; - fastcgi_param REQUEST_URI $request_uri; - fastcgi_param DOCUMENT_URI $document_uri; - fastcgi_param DOCUMENT_ROOT /var/www/html/; - fastcgi_param SERVER_PROTOCOL $server_protocol; + location ~ \.woff2?$ { + try_files $uri /index.php$request_uri; + expires 7d; + access_log off; + } - fastcgi_param GATEWAY_INTERFACE CGI/1.1; - fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; - - fastcgi_param REMOTE_ADDR $remote_addr; - fastcgi_param REMOTE_PORT $remote_port; - fastcgi_param SERVER_ADDR $server_addr; - fastcgi_param SERVER_PORT $server_port; - fastcgi_param SERVER_NAME $server_name; - - fastcgi_param HTTPS $https; - - # PHP only, required if PHP was built with --enable-force-cgi-redirect - fastcgi_param REDIRECT_STATUS 200; + location / { + try_files $uri $uri/ /index.php$request_uri; } + } diff --git a/vars/applications.yaml b/vars/applications.yaml index a9aad5d..16ae687 100644 --- a/vars/applications.yaml +++ b/vars/applications.yaml @@ -116,7 +116,7 @@ omni_compose_apps: name: mech_nextcloud uid: 1290 published: - host: wsd.enp.one + host: nxc.enp.one ports: 80: 8082 networks: @@ -129,3 +129,7 @@ omni_compose_apps: assets: - src: nginx/nextcloud-proxy.conf name: proxy/nextcloud.conf + - src: nextcloud-php-fpm.ini + name: config/php.ini + - src: nextcloud-mariadb.cnf + name: proxy/nextcloud.cnf