commit 2151907afe89ede2d62a4fb275f3074fbe43d325 Author: Lennard Brinkhaus Date: Sat Feb 3 22:12:59 2024 +0100 feat: initial full commit diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..ab9fdb4 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,19 @@ +# EditorConfig: http://EditorConfig.org + +# top-most EditorConfig file +root = true + +# Defaults for all editor files +[*] +insert_final_newline = true +indent_style = space +indent_size = 4 +trim_trailing_whitespace = true + +# Files with a smaller indent +[*.yml] +indent_size = 2 + +# Jinja2 template files +[*.j2] +end_of_line = lf \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ec2d6d9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,20 @@ +local-configure.yml +.vagrant/ +docs/_build/ +roles/plone.plone_server +roles/jnv.unattended-upgrades +roles/tersmitten.fail2ban +roles/ANXS.hostname +roles/ANXS.apt +._* +bin/ +lib/ +include/ +local/ +tests.out +*.retry +*.log +vbox_host.cfg +.DS_Store +*.py[co] +.idea/ \ No newline at end of file diff --git a/ansible.cfg b/ansible.cfg new file mode 100644 index 0000000..79ff805 --- /dev/null +++ b/ansible.cfg @@ -0,0 +1,2 @@ +[defaults] +roles_path: ./../ \ No newline at end of file diff --git a/defaults/main.yml b/defaults/main.yml new file mode 100644 index 0000000..26a425d --- /dev/null +++ b/defaults/main.yml @@ -0,0 +1,8 @@ +--- +nextcloud_version: "26" +nextcloud_redis_version: "7" +nextcloud_postgres_version: "16" +nextcloud_nginx_version: "alpine" + + +nextcloud_domains: ["nextcloud.test.intern"] diff --git a/handlers/main.yml b/handlers/main.yml new file mode 100644 index 0000000..6463f91 --- /dev/null +++ b/handlers/main.yml @@ -0,0 +1,24 @@ +- name: "Restart Paperless" + ansible.builtin.service: + name: paperless-ngx + state: restarted + +- name: "Restart Paperless Redis" + systemd_service: + name: paperless-ngx-redis + state: restarted + +- name: "Restart Paperless Tika" + systemd_service: + name: paperless-ngx-tika + state: restarted + +- name: "Restart Paperless Gotenberg" + systemd_service: + name: paperless-ngx-gotenberg + state: restarted + +- name: "Restart Paperless Postgres" + systemd_service: + name: paperless-ngx-postgres + state: restarted diff --git a/meta/main.yml b/meta/main.yml new file mode 100644 index 0000000..cc10069 --- /dev/null +++ b/meta/main.yml @@ -0,0 +1,56 @@ +galaxy_info: + author: Lennard Brinkhaus + description: Install and manage a Nextcloud Instance + company: DragSE + + # If the issue tracker for your role is not on github, uncomment the + # next line and provide a value + # issue_tracker_url: http://example.com/issue/tracker + + # Choose a valid license ID from https://spdx.org - some suggested licenses: + # - BSD-3-Clause (default) + # - MIT + # - GPL-2.0-or-later + # - GPL-3.0-only + # - Apache-2.0 + # - CC-BY-4.0 + license: None + + min_ansible_version: 2.1 + + # If this a Container Enabled role, provide the minimum Ansible Container version. + # min_ansible_container_version: + + # + # Provide a list of supported platforms, and for each platform a list of versions. + # If you don't wish to enumerate all versions for a particular platform, use 'all'. + # To view available platforms and versions (or releases), visit: + # https://galaxy.ansible.com/api/v1/platforms/ + # + # platforms: + # - name: Fedora + # versions: + # - all + # - 25 + # - name: SomePlatform + # versions: + # - all + # - 1.0 + # - 7 + # - 99.99 + + galaxy_tags: [ + nextcloud + ] + # List tags for your role here, one per line. A tag is a keyword that describes + # and categorizes the role. Users find roles by searching for tags. Be sure to + # remove the '[]' above, if you add tags to this list. + # + # NOTE: A tag is limited to a single word comprised of alphanumeric characters. + # Maximum 20 tags per role. + +dependencies: [ + role-traefik +] + # List your role dependencies here, one per line. Be sure to remove the '[]' above, +# if you add dependencies to this list. diff --git a/meta/requirements.yml b/meta/requirements.yml new file mode 100644 index 0000000..37553ac --- /dev/null +++ b/meta/requirements.yml @@ -0,0 +1,2 @@ +- name: role-traefik + src: https://git.dragse.it/ansible/role-traefik diff --git a/tasks/main.yml b/tasks/main.yml new file mode 100644 index 0000000..a314db1 --- /dev/null +++ b/tasks/main.yml @@ -0,0 +1,103 @@ +--- +- name: Create podman folder + file: + path: /etc/containers/systemd + state: directory + mode: 0775 + recurse: yes + +- name: Create nextcloud folder + file: + path: "/var/nextcloud/app" + state: directory + mode: 0775 + recurse: yes + +- name: Create nginx folder + file: + path: "/var/nextcloud/web" + state: directory + mode: 0775 + recurse: yes + +- name: Create paperless redis folder + file: + path: "/var/nextcloud/redis" + state: directory + mode: 0775 + recurse: yes + +- name: Create paperless postgres folder + file: + path: "/var/nextcloud/postgres" + state: directory + mode: 0775 + recurse: yes + +- name: Copy nginx.conf + ansible.builtin.template: + src: nginx.conf.j2 + dest: "/var/nextcloud/web/nginx.conf" + +- name: Setup Podman quadlet + block: + - name: Copy nextcloud.network + ansible.builtin.template: + src: nextcloud.network + dest: "/etc/containers/systemd/nextcloud.network" + + - name: Copy nextcloud-app.container + ansible.builtin.template: + src: nextcloud-app.quadlet.j2 + dest: "/etc/containers/systemd/nextcloud-app.container" + + - name: Copy nextcloud-cron.container + ansible.builtin.template: + src: nextcloud-cron.quadlet.j2 + dest: "/etc/containers/systemd/nextcloud-cron.container" + + - name: Copy nextcloud-postgres.container + ansible.builtin.template: + src: nextcloud-postgres.quadlet.j2 + dest: "/etc/containers/systemd/nextcloud-postgres.container" + + - name: Copy nextcloud-redis.container + ansible.builtin.template: + src: nextcloud-redis.quadlet.j2 + dest: "/etc/containers/systemd/nextcloud-redis.container" + + - name: Copy nextcloud-web.container + ansible.builtin.template: + src: paperless-ngx-tika.quadlet.j2 + dest: "/etc/containers/systemd/nextcloud-web.container" + + - name: "Reload systemd" + ansible.builtin.systemd: + daemon_reload: true + when: ansible_service_mgr == "systemd" + + - name: Start Paperless-ngs Redis + systemd_service: + enabled: true + name: paperless-ngx-redis + state: started + + - name: Start Paperless-ngs Tika + systemd_service: + enabled: true + name: paperless-ngx-tika + state: started + + - name: Start Paperless-ngs Gotenberg + systemd_service: + enabled: true + name: paperless-ngx-gotenberg + state: started + + - name: Start Paperless-ngs Postgres + systemd_service: + enabled: true + name: paperless-ngx-postgres + state: started + notify: + - Restart Paperless diff --git a/templates/nextcloud-app.quadlet.j2 b/templates/nextcloud-app.quadlet.j2 new file mode 100644 index 0000000..cf08f5b --- /dev/null +++ b/templates/nextcloud-app.quadlet.j2 @@ -0,0 +1,38 @@ +[Unit] +Description=Nextcloud App + +Requires=nextcloud-postgres.service +Requires=nextcloud-redis.service +After=nextcloud-postgres.service +After=nextcloud-redis.service + +[Container] +ContainerName=nextcloud-app +Image=docker.io/library/nextcloud:{{ nextcloud_version }}-fpm-alpine + +Environment=REDIS_HOST=nextcloud-redis +Environment=POSTGRES_HOST=nextcloud-postgres +Environment=POSTGRES_USER=nextcloud +Environment=POSTGRES_PASSWORD=nextcloud +Environment=POSTGRES_DB=nextcloud + +Environment=NEXTCLOUD_TRUSTED_DOMAINS=(% for domain in nextcloud_domains %){{domain}} (% endfor %) + + +Network=nextcloud.network + +Volume=/var/nextcloud/app:/var/www/html:z + +Label="traefik.enable=false" + +[Service] +Restart=on-failure +# Restart Delay +RestartSec=30 +# Allowed time for the service to start. +TimeoutStartSec=90 +# Allowed time for the service to stop. +TimeoutStopSec=90 + +[Install] +WantedBy=default.target diff --git a/templates/nextcloud-cron.quadlet.j2 b/templates/nextcloud-cron.quadlet.j2 new file mode 100644 index 0000000..3929750 --- /dev/null +++ b/templates/nextcloud-cron.quadlet.j2 @@ -0,0 +1,30 @@ +[Unit] +Description=Nextcloud Cron + +Requires=nextcloud-postgres.service +Requires=nextcloud-redis.service +After=nextcloud-postgres.service +After=nextcloud-redis.service + +[Container] +ContainerName=nextcloud-cron +Image=docker.io/library/nextcloud:{{ nextcloud_version }}-fpm-alpine +Entrypoint=/cron.sh + +Network=nextcloud.network + +Volume=/var/nextcloud/app:/var/www/html:z + +Label="traefik.enable=false" + +[Service] +Restart=on-failure +# Restart Delay +RestartSec=30 +# Allowed time for the service to start. +TimeoutStartSec=90 +# Allowed time for the service to stop. +TimeoutStopSec=90 + +[Install] +WantedBy=default.target diff --git a/templates/nextcloud-postgres.quadlet.j2 b/templates/nextcloud-postgres.quadlet.j2 new file mode 100644 index 0000000..f3b4516 --- /dev/null +++ b/templates/nextcloud-postgres.quadlet.j2 @@ -0,0 +1,29 @@ +[Unit] +Description=Nextcloud Postgres + +[Container] +ContainerName=nextcloud-postgres +Image=docker.io/library/postgres:{{ nextcloud_postgres_version }} + +Environment=TZ=Europe/Berlin +Environment=POSTGRES_USER=nextcloud +Environment=POSTGRES_PASSWORD=nextcloud +Environment=POSTGRES_DB=nextcloud + +Network=nextcloud.network + +Volume=/var/nextcloud/postgres:/var/lib/postgresql/data:rw + +Label="traefik.enable=false" + +[Service] +Restart=on-failure +# Restart Delay +RestartSec=30 +# Allowed time for the service to start. +TimeoutStartSec=90 +# Allowed time for the service to stop. +TimeoutStopSec=90 + +[Install] +WantedBy=default.target diff --git a/templates/nextcloud-redis.quadlet.j2 b/templates/nextcloud-redis.quadlet.j2 new file mode 100644 index 0000000..1023fbc --- /dev/null +++ b/templates/nextcloud-redis.quadlet.j2 @@ -0,0 +1,22 @@ +[Unit] +Description=Nextcloud Redis + +[Container] +ContainerName=nextcloud-redis +Image=docker.io/library/redis:{{ nextcloud_redis_version }} + +Network=nextcloud.network + +Label="traefik.enable=false" + +[Service] +Restart=on-failure +# Restart Delay +RestartSec=30 +# Allowed time for the service to start. +TimeoutStartSec=90 +# Allowed time for the service to stop. +TimeoutStopSec=90 + +[Install] +WantedBy=default.target diff --git a/templates/nextcloud-web.quadlet.j2 b/templates/nextcloud-web.quadlet.j2 new file mode 100644 index 0000000..b39da6b --- /dev/null +++ b/templates/nextcloud-web.quadlet.j2 @@ -0,0 +1,35 @@ +[Unit] +Description=Nextcloud Web + +Requires=nextcloud-app.service +After=nextcloud-app.service + +[Container] +ContainerName=nextcloud-web +Image=docker.io/library/nginx:{{ nextcloud_nginx_version }} + +Network=traefik.network +Network=nextcloud.network + +Volume=/var/nextcloud/web/nginx.conf:/etc/nginx/nginx.conf +Volume=/var/nextcloud/app:/var/www/html:z + +(% for domain in nextcloud_domains %) +Label="traefik.http.routers.nextcloud{{loop.index}}.tls.certresolver=resolver" +Label="traefik.http.routers.nextcloud{{loop.index}}.tls=true" +Label="traefik.http.routers.nextcloud{{loop.index}}.rule=Host(`{{ domain }}`)" +Label="traefik.http.routers.nextcloud{{loop.index}}.service=nextcloud{{loop.index}}" +Label="traefik.http.services.nextcloud{{loop.index}}.loadbalancer.server.port=80" +(% endfor %) + +[Service] +Restart=on-failure +# Restart Delay +RestartSec=30 +# Allowed time for the service to start. +TimeoutStartSec=90 +# Allowed time for the service to stop. +TimeoutStopSec=90 + +[Install] +WantedBy=default.target diff --git a/templates/nextcloud.network b/templates/nextcloud.network new file mode 100644 index 0000000..f311995 --- /dev/null +++ b/templates/nextcloud.network @@ -0,0 +1,2 @@ +[Network] +Label=app=nextcloud diff --git a/templates/nginx.conf.j2 b/templates/nginx.conf.j2 new file mode 100644 index 0000000..64f5fcd --- /dev/null +++ b/templates/nginx.conf.j2 @@ -0,0 +1,204 @@ +worker_processes auto; + +error_log /var/log/nginx/error.log warn; +pid /var/run/nginx.pid; + + +events { + worker_connections 1024; +} + + +http { + include mime.types; + default_type application/octet-stream; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /var/log/nginx/access.log main; + + sendfile on; + #tcp_nopush on; + + # Prevent nginx HTTP Server Detection + server_tokens off; + + keepalive_timeout 65; + + # Set the `immutable` cache control options only for assets with a cache busting `v` argument + map $arg_v $asset_immutable { + "" ""; + default "immutable"; + } + + #gzip on; + + upstream php-handler { + server nextcloud-app:9000; + } + + server { + listen 80; + + # HSTS settings + # 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 Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;" always; + + # set max upload size and increase upload timeout: + client_max_body_size 512M; + client_body_timeout 300s; + fastcgi_buffers 64 4K; + + # The settings allows you to optimize the HTTP2 bandwidth. + # See https://blog.cloudflare.com/delivering-http-2-upload-speed-improvements/ + # for tuning hints + client_body_buffer_size 512k; + + # 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 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; + + # Pagespeed is not supported by Nextcloud, so if your server is built + # with the `ngx_pagespeed` module, uncomment this line to disable it. + #pagespeed off; + + # 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; + + # Path to the root of your installation + root /var/www/html; + + # Specify how to handle directories -- specifying `/index.php$request_uri` + # here as the fallback means that Nginx always exhibits the desired behaviour + # when a client requests a path that corresponds to a directory that exists + # on the server. In particular, if that directory contains an index.php file, + # that file is correctly served; if it doesn't, then the request is passed to + # the front-end controller. This consistent behaviour means that we don't need + # to specify custom rules for certain paths (e.g. images and other assets, + # `/updater`, `/ocm-provider`, `/ocs-provider`), and thus + # `try_files $uri $uri/ /index.php$request_uri` + # always provides the desired behaviour. + 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; + + fastcgi_intercept_errors on; + fastcgi_request_buffering off; + + fastcgi_max_temp_file_size 0; + } + + # Javascript mimetype fixes for nginx + # Note: The block below should be removed, and the js|mjs section should be + # added to the block below this one. This is a temporary fix until Nginx + # upstream fixes the js mime-type + location ~* \.(?:js|mjs)$ { + types { + text/javascript js mjs; + } + try_files $uri /index.php$request_uri; + add_header Cache-Control "public, max-age=15778463, $asset_immutable"; + access_log off; + } + + # Serve static files + location ~ \.(?:css|svg|gif|png|jpg|ico|wasm|tflite|map|ogg|flac)$ { + 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; + } + } +} diff --git a/tests/inventory b/tests/inventory new file mode 100644 index 0000000..ac96836 --- /dev/null +++ b/tests/inventory @@ -0,0 +1 @@ +192.168.1.142 diff --git a/tests/test.yml b/tests/test.yml new file mode 100644 index 0000000..e69de29 diff --git a/vars/main.yml b/vars/main.yml new file mode 100644 index 0000000..ed97d53 --- /dev/null +++ b/vars/main.yml @@ -0,0 +1 @@ +---