diff --git a/README.md b/README.md index e193e92..64911cf 100644 --- a/README.md +++ b/README.md @@ -69,6 +69,10 @@ php_cli_config: | `database` | string | Name der anzulegenden Datenbank | | `database_type` | string | `MariaDB` oder `PostgreSQL` | | `hiddenservice` | bol | Richtet für die Instanz einen Onion Service ein | +- Lege in den `host_vars` den Webserver-Typ fest: + | Variable | Wert | Beschreibung | + |----------|------|--------------| + | `nextcloud_webserver` | string | `Apache` oder `Nginx` | - Starte anschließend das Playbook: ```Shell ansible-playbook playbooks/nextcloud.yml diff --git a/defaults/main.yml b/defaults/main.yml index 84bbb30..a381e87 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -4,7 +4,6 @@ apache_custom_conf_path: /etc/apache2/conf-available nextcloud_admin_user: systemausfall.org nextcloud_admin_pw: "{{ lookup('password', '/tmp/{{ item.name }}_admin_pwd length=42 chars=ascii_letters,digits') }}" nextcloud_db_password: "{{ lookup('password', '/tmp/{{ item.name }}_db_pwd length=42 chars=ascii_letters,digits') }}" -nextcloud_db_type: MariaDB nextcloud_github_api_url: https://api.github.com/repos/nextcloud/server/releases/latest nextcloud_dl_url: "https://download.nextcloud.com/server/releases/nextcloud-{{ latest_version.stdout }}.tar.bz2" nextcloud_root: /data/nextcloud @@ -12,5 +11,6 @@ nextcloud_install_path: "{{ nextcloud_root }}/{{ item.name }}" nextcloud_config_file: "{{ nextcloud_install_path }}/config/config.php" nextcloud_php_memory_limit: 1G nextcloud_php_upload_limit: 1G +nextcloud_webserver: Apache redis_config_file: /etc/redis/redis.conf diff --git a/tasks/apache.yml b/tasks/apache.yml deleted file mode 100644 index f36502c..0000000 --- a/tasks/apache.yml +++ /dev/null @@ -1,35 +0,0 @@ ---- -- name: "Apache | Aktiviere Apache-Module" - community.general.apache2_module: - name: "{{ item.name }}" - state: "{{ item.state | default('present') }}" - loop: - - name: env - - name: expires - - name: headers - - name: macro - - name: mpm_event - - name: mpm_prefork - state: absent - - name: proxy_fcgi - - name: setenvif - notify: restart apache - -- name: "Apache | Richte Nextcloud-Seiten ein" - ansible.builtin.template: - src: apache2/nextcloud_sites.conf.j2 - dest: /etc/apache2/conf-available/nextcloud_sites.conf - mode: "0644" - notify: reload apache - -- name: "Apache | Kopiere Apache-Vorlage für Seitenkonfiguration" - ansible.builtin.template: - src: apache2/nextcloud.conf.j2 - dest: /etc/apache2/sites-available/nextcloud.conf - mode: "0644" - -- name: "Apache | Aktiviere Apache-Seitenkonfiguration" - ansible.builtin.command: - cmd: a2ensite nextcloud.conf - creates: /etc/apache2/sites-enabled/nextcloud.conf - notify: reload apache diff --git a/tasks/main.yml b/tasks/main.yml index 5c8c5a5..7df364e 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -55,8 +55,8 @@ when: item.hiddenservice is defined - name: Run Webserver tasks - ansible.builtin.import_tasks: apache.yml - tags: apache + ansible.builtin.import_tasks: webserver.yml + tags: webserver - name: Installation ansible.builtin.include_tasks: nextcloud.yml diff --git a/tasks/webserver.yml b/tasks/webserver.yml new file mode 100644 index 0000000..400e65a --- /dev/null +++ b/tasks/webserver.yml @@ -0,0 +1,57 @@ +--- +- name: "Konfiguriere Apache" + when: nextcloud_webserver == "Apache" + tags: apache + block: + - name: "Webserver | Aktiviere Apache-Module" + community.general.apache2_module: + name: "{{ item.name }}" + state: "{{ item.state | default('present') }}" + loop: + - name: env + - name: expires + - name: headers + - name: macro + - name: mpm_event + - name: mpm_prefork + state: absent + - name: proxy_fcgi + - name: setenvif + notify: restart apache + + - name: "Webserver | Richte Nextcloud-Seiten ein" + ansible.builtin.template: + src: apache2/nextcloud_sites.conf.j2 + dest: /etc/apache2/conf-available/nextcloud_sites.conf + mode: "0644" + notify: reload apache + + - name: "Webserver | Kopiere Apache-Vorlage für Seitenkonfiguration" + ansible.builtin.template: + src: apache2/nextcloud.conf.j2 + dest: /etc/apache2/sites-available/nextcloud.conf + mode: "0644" + + - name: "Webserver | Aktiviere Apache-Seitenkonfiguration" + ansible.builtin.command: + cmd: a2ensite nextcloud.conf + creates: /etc/apache2/sites-enabled/nextcloud.conf + notify: reload apache + +- name: "Konfiguriere Nginx" + when: nextcloud_webserver == "Nginx" + tags: nginx + loop: "{{ nextcloud_instances }}" + notify: Reload nginx + block: + - name: "Webserver | Kopiere Nginx-Konfiguration" + ansible.builtin.template: + src: nginx/nginx.conf + dest: "/etc/nginx/sites-available/{{ item.name }}" + mode: "0644" + + - name: "Webserver | Aktiviere Nginx-Konfiguration" + ansible.builtin.file: + src: "/etc/nginx/sites-available/{{ item.name }}" + dest: "/etc/nginx/sites-enabled/{{ item.name }}" + state: link diff --git a/templates/nginx/nginx.conf b/templates/nginx/nginx.conf new file mode 100644 index 0000000..811df91 --- /dev/null +++ b/templates/nginx/nginx.conf @@ -0,0 +1,135 @@ +upstream php-handler-{{ item.user }} { + server unix:/run/php/php-fpm-{{ item.user }}.sock; +} + +map $arg_v $asset_immutable { + "" ""; + default "immutable"; +} + +server { + listen 80; + listen [::]:80; + server_name {{ item.name }}; + root {{ nextcloud_install_path }} + + client_max_body_size {{ nextcloud_php_upload_limit }}; + client_body_timeout 600s; + client_body_buffer_size 512k; + 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 text/javascript application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/wasm 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; + + # HTTP response headers borrowed from Nextcloud `.htaccess` + add_header Referrer-Policy "no-referrer" always; + add_header X-Content-Type-Options "nosniff" always; + add_header X-Frame-Options "SAMEORIGIN" always; + add_header X-Permitted-Cross-Domain-Policies "none" always; + add_header X-Robots-Tag "noindex, nofollow" 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; + + include mime.types; + types { + text/javascript mjs; + } + + index index.php index.html /index.php$request_uri; + + # Rule borrowed from `.htaccess` to handle Microsoft DAV clients + 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; + } + + # Make a regex exception for `/.well-known` so that clients can still + # access it despite the existence of the regex rule + # `location ~ /(\.|autotest|...)` which would otherwise handle requests + # for `/.well-known`. + location ^~ /.well-known { + # The rules in this block are an adaptation of the rules + # in `.htaccess` that concern `/.well-known`. + + location = /.well-known/carddav { return 301 /remote.php/dav/; } + location = /.well-known/caldav { return 301 /remote.php/dav/; } + + location /.well-known/acme-challenge { try_files $uri $uri/ =404; } + location /.well-known/pki-validation { try_files $uri $uri/ =404; } + + # Let Nextcloud's API for `/.well-known` URIs handle all other + # requests by passing them to the front-end controller. + return 301 /index.php$request_uri; + } + + # Rules borrowed from `.htaccess` to hide certain paths from clients + location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)(?:$|/) { return 404; } + location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console) { return 404; } + + # Ensure this block, which passes PHP files to the PHP process, is above the blocks + # which handle static assets (as seen below). If this block is not declared first, + # then Nginx will encounter an infinite rewriting loop when it prepends `/index.php` + # to the URI, resulting in a HTTP 500 error response. + location ~ \.php(?:$|/) { + # Required for legacy support + rewrite ^/(?!index|remote|public|cron|core\/ajax\/update|status|ocs\/v[12]|updater\/.+|ocs-provider\/.+|.+\/richdocumentscode\/proxy) /index.php$request_uri; + + fastcgi_split_path_info ^(.+?\.php)(/.*)$; + set $path_info $fastcgi_path_info; + + try_files $fastcgi_script_name =404; + + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_param PATH_INFO $path_info; + fastcgi_param HTTPS on; + + fastcgi_param modHeadersAvailable true; # Avoid sending the security headers twice + fastcgi_param front_controller_active true; # Enable pretty urls + fastcgi_pass php-handler-{{ item.user }}; + + fastcgi_intercept_errors on; + fastcgi_request_buffering off; + + fastcgi_max_temp_file_size 0; + } + + # Serve static files + location ~ \.(?:css|js|mjs|svg|gif|png|jpg|ico|wasm|tflite|map)$ { + try_files $uri /index.php$request_uri; + add_header Cache-Control "public, max-age=15778463, $asset_immutable"; + access_log off; # Optional: Don't log access to assets + + location ~ \.wasm$ { + default_type application/wasm; + } + } + + location ~ \.woff2?$ { + try_files $uri /index.php$request_uri; + expires 7d; # Cache-Control policy borrowed from `.htaccess` + access_log off; # Optional: Don't log access to assets + } + + # Rule borrowed from `.htaccess` + location /remote { + return 301 /remote.php$request_uri; + } + + location / { + try_files $uri $uri/ /index.php$request_uri; + } +}