diff --git a/README.md b/README.md new file mode 100644 index 0000000..92f6786 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# nextcloud diff --git a/defaults/main.yml b/defaults/main.yml new file mode 100644 index 0000000..395be08 --- /dev/null +++ b/defaults/main.yml @@ -0,0 +1,22 @@ +path: /srv/{{ role_name }} + +nextcloud_override: {} +nextcloud_defaults: + url: "" + data_path: "" + db_password: "" + secret: "" + secret_salt: "" + mail: {} + oidc: + issuer: "" + client_id: "" + client_secret: "" + id_attribute: "user_id" + quota_attribute: "quota" + + collabora: + password: "" + url: "" + drawio: + url: "" diff --git a/theme/main.css b/files/theme/main.css similarity index 100% rename from theme/main.css rename to files/theme/main.css diff --git a/theme/main.scss b/files/theme/main.scss similarity index 100% rename from theme/main.scss rename to files/theme/main.scss diff --git a/handlers/main.yml b/handlers/main.yml new file mode 100644 index 0000000..b7d9c67 --- /dev/null +++ b/handlers/main.yml @@ -0,0 +1,9 @@ +- name: restart container +community.docker.docker_compose_v2: + project_src: "{{ path }}" + project_name: "{{ role_name }}" + recreate: "always" + services: ["nextcloud"] + state: "restarted" +when: not _nextcloud_already_restarted + diff --git a/meta/main.yml b/meta/main.yml new file mode 100644 index 0000000..3223c58 --- /dev/null +++ b/meta/main.yml @@ -0,0 +1,20 @@ +--- +galaxy_info: + author: "Niklas Freese " + description: nextcloud + company: "Urmel Services" + license: AGPL-3.0-or-later + min_ansible_version: 2.1 + # If this a Container Enabled role, provide the minimum Ansible Container version. + # min_ansible_container_version: + + galaxy_tags: [] + # 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: base diff --git a/tasks/main.yml b/tasks/main.yml new file mode 100644 index 0000000..73ad836 --- /dev/null +++ b/tasks/main.yml @@ -0,0 +1,59 @@ +--- +- name: "set local variables from overrides and defaults" + set_fact: + nextcloud: "{{ (nextcloud_defaults | combine(nextcloud_override, recursive=True)) if nextcloud_override else nextcloud_defaults }}" + +- name: ensure that path exists + file: + path: "{{ path }}/config/nextcloud" + state: directory + +- name: template compose + template: + src: compose.yml.j2 + dest: "{{ path }}/compose.yml" + +- name: template nc config + template: + src: importconfig.json.j2 + dest: "{{ path }}/config/nextcloud/importconfig.json" + register: _importconfig + +- block: + - name: recreate nextcloud so the configfile gets updated + community.docker.docker_compose_v2: + project_src: "{{ path }}" + project_name: "{{ role_name }}" + state: present + recreate: always + services: "nextcloud" + wait: true + + - name: import config + community.docker.docker_container_exec: + container: "{{ nextcloud_container }}" + chdir: "/var/www/html/" + user: "www-data" + command: "php occ config:import /tmp/importconfig.json" + when: "_importconfig.changed or 'installed: false' in nextcloud_status_check.stdout" + +- name: ensure containers are running + community.docker.docker_compose_v2: + project_src: "{{ path }}" + project_name: "{{ role_name }}" + state: "present" + pull: "always" + wait: true + services: >- + {{ ['db', 'redis', 'nextcloud'] + + (['collabora'] if nextcloud.collabora.url | default('') else []) + + (['drawio'] if nextcloud.drawio.url | default('') else []) }} + register: _compose_result + +- name: import config + community.docker.docker_container_exec: + container: "{{ nextcloud_container }}" + chdir: "/var/www/html/" + user: "www-data" + command: "php occ config:import /tmp/importconfig.json" + when: "_importconfig.changed or 'installed: false' in nextcloud_status_check.stdout" diff --git a/compose.yml b/templates/compose.yml.j2 similarity index 52% rename from compose.yml rename to templates/compose.yml.j2 index 8bcc299..427f0d6 100644 --- a/compose.yml +++ b/templates/compose.yml.j2 @@ -1,4 +1,3 @@ -version: '2' services: db: image: mariadb:10.6 @@ -6,28 +5,47 @@ services: hostname: maria-db command: --transaction-isolation=READ-COMMITTED --log-bin=binlog --binlog-format=ROW networks: - - db-con + - internal volumes: - - db:/var/lib/mysql + - ./data/db:/var/lib/mysql environment: - - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD} - - MYSQL_PASSWORD=${MYSQL_ROOT_PASSWORD} + - MYSQL_ROOT_PASSWORD={{ nextcloud.db_password }} + - MYSQL_PASSWORD={{ nextcloud.db_password }} - MYSQL_DATABASE=nextcloud - MYSQL_USER=nextcloud - - app: + + redis: + image: redis:latest + restart: always + networks: + - internal + command: > + --appendonly yes + --tcp-backlog 511 --databases 16 + --save 900 1 --save 300 10 --save 60 10000 + --maxclients 512 + volumes: + - "./data/redis:/data" + healthcheck: + test: [ "CMD", "redis-cli", "ping" ] + interval: 10s + timeout: 5s + retries: 5 + + nextcloud: image: nextcloud:32.0.5 hostname: nextcloud restart: always networks: - proxy - - db-con + - internal volumes: - - nextcloud:/var/www/html - - nextcloud_hooks:/docker-entrypoint-hooks.d - - /etc/localtime:/etc/localtime:ro + - {{ nextcloud.data_path }}:/var/www/html + - ./config/hooks:/docker-entrypoint-hooks.d + - "./config/nextcloud-importconfig.json:/tmp/importconfig.json:ro" + - /etc/localtime:/etc/localtime:ro environment: - - MYSQL_PASSWORD=${MYSQL_ROOT_PASSWORD} + - MYSQL_PASSWORD={{ nextcloud.db_password }} - MYSQL_DATABASE=nextcloud - MYSQL_USER=nextcloud - MYSQL_HOST=maria-db @@ -35,7 +53,7 @@ services: - PHP_UPLOAD_LIMIT=5120M labels: traefik.enable: true - traefik.http.routers.nextcloud.rule: "Host(`nextcloud.urmel.de`)" + traefik.http.routers.nextcloud.rule: "Host(`{{ nextcloud.url }}`)" traefik.http.routers.nextcloud.tls: true traefik.http.routers.nextcloud.tls.certResolver: hetzner traefik.http.services.nextcloud-https.loadbalancer.server.port: 80 @@ -46,24 +64,20 @@ services: traefik.http.middlewares.nextcloud-dav.redirectRegex.replacement: https://$${1}/remote.php/dav/ traefik.http.middlewares.nextcloud-dav.redirectRegex.permanent: true traefik.http.middlewares.nextcloud-header.headers.stsSeconds: "15552000" - # traefik.http.middlewares.nextcloud-header.headers.referrerPolicy: no-referrer - # traefik.http.middlewares.nextcloud-header.headers.forceSTSHeader: true - # traefik.http.middlewares.nextcloud-header.headers.stsPreload: true - # traefik.http.middlewares.nextcloud-header.headers.stsIncludeSubdomains: true - # traefik.http.middlewares.nextcloud-header.headers.browserXssFilter: true - # traefik.http.middlewares.nextcloud-header.headers.customRequestHeaders.X-Forwarded-Proto: https + +{% if nextcloud.collabora.url %} collabora: image: collabora/code:25.04.8.1.1 hostname: collabora networks: - proxy environment: - - aliasgroup1=https://nextcloud.urmel.de + - aliasgroup1="https://{{ nextcloud.url }}" - DONT_GEN_SSL_CERT=YES - - domain=collabora.urmel.de - - VIRTUAL_HOST=collabora.urmel.de + - domain="{{ nextcloud.collabora.url }}" + - VIRTUAL_HOST="{{ nextcloud.collabora.url }}" - username=someAdmin - - password=${COLLABORA_PASSWORD} + - password="{{ nextcloud.collabora.password }}" - extra_params=--o:ssl.enable=false --o:ssl.termination=true --o:net.wopi.host=nextcloud.urmel.de --o:logging.disable_server_audit=true cap_add: - CHOWN @@ -84,24 +98,15 @@ services: retries: 5 labels: traefik.enable: true - traefik.http.routers.collabora.rule: "Host(`collabora.urmel.de`)" + traefik.http.routers.collabora.rule: "Host(`{{ nextcloud.collabora.url }}`)" traefik.http.routers.collabora.tls: true traefik.http.routers.collabora.tls.certResolver: hetzner traefik.http.services.collabora-https.loadbalancer.server.port: 9980 traefik.http.services.collabora-https.loadbalancer.passHostHeader: true - # traefik.http.middlewares.collabora-headers.headers.customrequestheaders.Connection: Upgrade - # traefik.http.middlewares.collabora-headers.headers.customrequestheaders.Upgrade: websocket - # traefik.http.middlewares.collabora-headers.headers.customrequestheaders.X-Forwarded-Proto: https - # traefik.http.middlewares.collabora-headers.headers.customrequestheaders.X-Forwarded-Host: collabora.urmel.de - # traefik.http.middlewares.collabora-headers.headers.referrerPolicy: no-referrer - # traefik.http.middlewares.collabora-headers.headers.stsSeconds: 15552000 - # traefik.http.middlewares.collabora-headers.headers.forceSTSHeader: true - # traefik.http.middlewares.collabora-headers.headers.stsPreload: true - # traefik.http.middlewares.collabora-headers.headers.stsIncludeSubdomains: true - # traefik.http.middlewares.collabora-headers.headers.browserXssFilter: true - # traefik.http.middlewares.collabora-headers.headers.customRequestHeaders.X-Forwarded-Proto: https - # traefik.http.routers.collabora.middlewares: collabora-headers +{% endif %} + +{% if nextcloud.drawio.url %} drawio: image: jgraph/drawio:29.3.5 hostname: drawio @@ -109,24 +114,14 @@ services: - proxy labels: traefik.enable: true - traefik.http.routers.drawio.rule: "Host(`drawio.urmel.de`)" + traefik.http.routers.drawio.rule: "Host(`{{ nextcloud.drawio.url }}`)" traefik.http.routers.drawio.tls: true traefik.http.routers.drawio.tls.certResolver: hetzner traefik.http.services.drawio-https.loadbalancer.server.port: 8080 - - -volumes: - nextcloud: - driver_opts: - type: nfs4 - o: addr=217.100.0.2,rw,noatime,tcp - device: ":/mnt/Main/nextcloudData" - nextcloud_hooks: - db: networks: proxy: name: traefik_exposed external: true - db-con: - internal: true \ No newline at end of file + internal: + internal: true diff --git a/templates/importconfig.json.j2 b/templates/importconfig.json.j2 new file mode 100644 index 0000000..166c129 --- /dev/null +++ b/templates/importconfig.json.j2 @@ -0,0 +1,92 @@ +{ + "system": { + "htaccess.RewriteBase": "/", + "memcache.local": "\\OC\\Memcache\\APCu", + "memcache.locking": "\\OC\\Memcache\\Redis", + "memcache.distributed": "\\OC\\Memcache\\Redis", + "redis": { + "host": "redis", + "port": "6379" + }, + "upgrade.disable-web": true, + "instanceid": "ocm6kh4i5s9r", + "passwordsalt": "{{ nextcloud.secretsalt }}", + "secret": "{{ nextcloud.secret }}", + "apache_disable_rewrite_ip": true, + "trusted_proxies": [ + "172.18.0.0/16" + ], + "trusted_domains": [ + "{{ nextcloud.url }}" + ], + "overwrite.cli.url": "https://{{ nextcloud.url }}", + "overwriteprotocol": "https", + + {% if nextcloud.oidc.issuer -%} + "oidc_login_provider_url": "{{ nextcloud.oidc.issuer }}", + "oidc_login_client_id": "{{ nextcloud.oidc.client_id }}", + "oidc_login_client_secret": "{{ nextcloud.oidc.client_secret }}", + "oidc_login_auto_redirect": true, + "oidc_login_logout_url": "{{ nextcloud.oidc.issuer }}", + "oidc_login_end_session_redirect": true, + "oidc_login_hide_password_form": false, + "oidc_login_use_id_token": false, + + "oidc_login_attributes": { + "id": "{{ nextcloud.oidc.id_attribute }}", + "name": "name", + "mail": "email", + "quota": "{{ nextcloud.oidc.id_attribute }}", + }, + "oidc_login_scope": "email profile nextcloud openid", + + "oidc_login_proxy_ldap": false, + "oidc_login_disable_registration": false, + "oidc_login_password_authentication": true, + "oidc_login_update_avatar": true, + "oidc_create_groups": true, + {%- endif %} + + "datadirectory": "/var/www/html/data", + "dbtype": "mysql", + "version": "32.0.5.0", + "dbname": "nextcloud", + "dbhost": "db", + "dbport": "", + "dbtableprefix": "oc_", + "mysql.utf8mb4": true, + "dbuser": "nextcloud", + "dbpassword": "{{ nextcloud.db_password }}", + "installed": true, + "maintenance_window_start": 100, + "enabledPreviewProviders": [ + "OC\\Preview\\Image", + "OC\\Preview\\HEIC", + "OC\\Preview\\TIFF", + "OC\\Preview\\Movie" + ], + "preview_max_x": 2048, + "preview_max_y": 2048, + "loglevel": 2, + "opcache.memory_consumption": 512, + "opcache.revalidate_freq": 60, + "default_phone_region": "DE", + "memories.gis_type": 1, + "mail_domain": "{{ mail.domain }}", + "mail_from_address": "noreply", + "mail_smtpmode": "smtp", + "mail_smtphost": "{{ mail.host }}", + "mail_smtpport": "587", + "mail_sendmailmode": "smtp", + "mail_smtpauth": true, + "mail_smtpname": "{{ mail.address }}", + "mail_smtppassword": "{{ mail.password }}", + "user_oidc": { + "auto_provision": true + }, + "forwarded_for_headers": [ + "HTTP_X_FORWARDED_FOR" + ], + "allow_local_remote_servers": true + } +}