--- # de Byl Technologies Nextcloud (cloud.debyltech.com). # # Cloned from containers/skudak/cloud.yml, which carries the full reasoning for # nearly every task below -- read the matching comment there before changing # one here. Comments in this file cover only where the two instances differ. # # Differences from Skudak, by design: # - Fresh install: NEXTCLOUD_ADMIN_* makes the first deploy install # unattended, and LibreSign is installed from the app store rather than # assumed present. # - No Group Folders. Registration stays off, matching Skudak's live state: # every account, staff and customer alike, is created by the admin, with # customers in per-customer groups. # - Outbound mail is AWS SES SMTP (noreply@debyltech.com), set here via occ # so it lives in git rather than only in the admin UI. # - Backups go to personal iDrive e2 via TrueNAS -- see the backup include # at the bottom. - name: create required debyltech cloud volumes become: true ansible.builtin.file: path: "{{ item }}" state: directory owner: "{{ podman_subuid.stdout }}" group: "{{ podman_subuid.stdout }}" mode: 0755 notify: restorecon podman loop: - "{{ cloud_debyltech_path }}/apps" - "{{ cloud_debyltech_path }}/config" - "{{ cloud_debyltech_path }}/data" - "{{ cloud_debyltech_path }}/mysql" - "{{ cloud_debyltech_path }}/scripts" - "{{ cloud_debyltech_path }}/redis" - name: unshare chown the debyltech cloud volumes become: true become_user: "{{ podman_user }}" changed_when: false ansible.builtin.command: | podman unshare chown -R 33:33 {{ cloud_debyltech_path }}/apps {{ cloud_debyltech_path }}/data {{ cloud_debyltech_path }}/config - name: flush handlers ansible.builtin.meta: flush_handlers - import_tasks: podman/podman-check.yml vars: container_name: debyltech-cloud-db container_image: "{{ db_image }}" - name: create debyltech-cloud-db container become: true become_user: "{{ podman_user }}" containers.podman.podman_container: name: debyltech-cloud-db image: "{{ db_image }}" restart_policy: on-failure:3 log_driver: journald network: - shared env: MYSQL_ROOT_PASSWORD: "{{ cloud_debyltech_db_root_pass }}" MYSQL_DATABASE: dtcloud MYSQL_PASSWORD: "{{ cloud_debyltech_db_pass }}" MYSQL_USER: dtcloud volumes: - "{{ cloud_debyltech_path }}/mysql:/var/lib/mysql" - name: create systemd startup job for debyltech-cloud-db include_tasks: podman/systemd-generate.yml vars: container_name: debyltech-cloud-db # --------------------------------------------------------------------------- # Redis: distributed cache + file locking. MUST exist before debyltech-cloud # below -- see the Skudak equivalent for why. - name: template debyltech cloud redis config become: true ansible.builtin.template: src: nextcloud/redis-debyltech.conf.j2 dest: "{{ cloud_debyltech_path }}/redis/redis.conf" owner: "{{ podman_subuid.stdout }}" group: "{{ podman_subuid.stdout }}" mode: 0640 notify: restorecon podman no_log: true - name: flush handlers ansible.builtin.meta: flush_handlers - name: unshare chown the debyltech redis config to the redis uid become: true become_user: "{{ podman_user }}" changed_when: false ansible.builtin.command: > podman unshare chown 999:1000 {{ cloud_debyltech_path }}/redis/redis.conf - import_tasks: podman/podman-check.yml vars: container_name: debyltech-cloud-redis container_image: "{{ redis_image }}" - name: create debyltech-cloud-redis container become: true become_user: "{{ podman_user }}" containers.podman.podman_container: name: debyltech-cloud-redis image: "{{ redis_image }}" restart_policy: on-failure:3 log_driver: journald network: - shared volumes: - "{{ cloud_debyltech_path }}/redis/redis.conf:/etc/redis/redis.conf:ro" command: redis-server /etc/redis/redis.conf - name: create systemd startup job for debyltech-cloud-redis include_tasks: podman/systemd-generate.yml vars: container_name: debyltech-cloud-redis - import_tasks: podman/podman-check.yml vars: container_name: debyltech-cloud container_image: "{{ image }}" - name: create debyltech cloud container become: true become_user: "{{ podman_user }}" containers.podman.podman_container: name: debyltech-cloud image: "{{ image }}" restart_policy: on-failure:3 log_driver: journald network: - shared env: MYSQL_PASSWORD: "{{ cloud_debyltech_db_pass }}" MYSQL_DATABASE: dtcloud MYSQL_HOST: debyltech-cloud-db MYSQL_USER: dtcloud # Read by the entrypoint ONLY on first start against an empty config # volume, to run the install unattended; ignored on every start after. NEXTCLOUD_ADMIN_USER: admin NEXTCLOUD_ADMIN_PASSWORD: "{{ cloud_debyltech_admin_pass }}" NEXTCLOUD_TRUSTED_DOMAINS: "{{ cloud_debyltech_server_name }}" PHP_MEMORY_LIMIT: 1024M PHP_UPLOAD_LIMIT: 512M LC_ALL: C.UTF-8 LANG: C.UTF-8 REDIS_HOST: debyltech-cloud-redis REDIS_HOST_PORT: "6379" REDIS_HOST_PASSWORD: "{{ cloud_debyltech_redis_pass }}" volumes: - "{{ cloud_debyltech_path }}/apps:/var/www/html/custom_apps" - "{{ cloud_debyltech_path }}/data:/var/www/html/data" - "{{ cloud_debyltech_path }}/config:/var/www/html/config" ports: - "8091:80" - name: create systemd startup job for debyltech-cloud include_tasks: podman/systemd-generate.yml vars: container_name: debyltech-cloud # --------------------------------------------------------------------------- # LibreSign - name: install libresign runtime dependencies in debyltech-cloud become: true become_user: "{{ podman_user }}" ansible.builtin.command: cmd: > podman exec -u 0 debyltech-cloud sh -c "apt-get update && apt-get install -y --no-install-recommends poppler-utils ghostscript && rm -rf /var/lib/apt/lists/*" register: libresign_deps changed_when: "'is already the newest version' not in libresign_deps.stdout" # On the FIRST deploy this also waits out the unattended install, which takes # noticeably longer than a restart -- hence the larger budget than Skudak's. - name: wait for nextcloud to be ready in debyltech-cloud become: true become_user: "{{ podman_user }}" ansible.builtin.command: > podman exec -u www-data debyltech-cloud php occ status --output=json register: debyltech_occ_ready # String match, not from_json: before the install finishes occ can print a # plain-text warning ahead of the JSON, and a parse error would abort the # retry loop instead of waiting. Skudak's bare 'installed' check would also # match "installed":false, which is exactly the state being waited out here. until: >- debyltech_occ_ready.rc == 0 and '"installed":true' in debyltech_occ_ready.stdout retries: 60 delay: 5 changed_when: false # LibreSign is PINNED (libresign_version / libresign_sha256 in tasks/main.yml) # and installed from the upstream GitHub release, NOT `occ app:install`, which # always takes whatever the app store has that day. On 2026-09-28 that was a # same-day 14.2.3 whose tarball shipped without appinfo/install-*.json -- the # maintainer-signed metadata LibreSign verifies its java/pdftk/jsignpdf # downloads against -- so configure:check failed all three on a clean install. # # Upgrading: bump both pins together (the sha256 is on the GitHub release # asset) and deploy; the tree is replaced and `occ upgrade` runs the app's # migrations. Downgrading is refused below: Nextcloud does not support it, and # the only way back is removing the app, which discards its config and CA. - name: read installed libresign version in debyltech-cloud become: true become_user: "{{ podman_user }}" ansible.builtin.command: > podman exec -u www-data debyltech-cloud php occ config:app:get libresign installed_version register: libresign_installed changed_when: false failed_when: false - name: refuse to downgrade libresign in debyltech-cloud ansible.builtin.fail: msg: >- LibreSign {{ libresign_installed.stdout }} is installed but the pin is {{ libresign_version }}. Nextcloud cannot downgrade an app in place -- raise the pin, or remove the app deliberately if nothing has been signed. when: - libresign_installed.rc == 0 - libresign_installed.stdout is version(libresign_version, '>') - name: install pinned libresign release in debyltech-cloud when: libresign_installed.rc != 0 or libresign_installed.stdout != libresign_version block: - name: fetch pinned libresign release become: true ansible.builtin.get_url: url: "https://github.com/LibreSign/libresign/releases/download/v{{ libresign_version }}/libresign-v{{ libresign_version }}.tar.gz" dest: "{{ cloud_debyltech_path }}/scripts/libresign-v{{ libresign_version }}.tar.gz" checksum: "sha256:{{ libresign_sha256 }}" mode: 0644 - name: remove previous libresign app tree become: true ansible.builtin.file: path: "{{ cloud_debyltech_path }}/apps/libresign" state: absent - name: unpack pinned libresign release into custom_apps become: true ansible.builtin.unarchive: src: "{{ cloud_debyltech_path }}/scripts/libresign-v{{ libresign_version }}.tar.gz" dest: "{{ cloud_debyltech_path }}/apps/" remote_src: true # Unpacked as root the files keep the tarball's owners, which lie # outside the podman user's subuid range, so the unshare chown below # is refused. Same two-step as the debyltechmail copy. owner: "{{ podman_subuid.stdout }}" group: "{{ podman_subuid.stdout }}" notify: restorecon podman - name: unshare chown the libresign app tree become: true become_user: "{{ podman_user }}" changed_when: false ansible.builtin.command: > podman unshare chown -R 33:33 {{ cloud_debyltech_path }}/apps/libresign - name: flush handlers ansible.builtin.meta: flush_handlers # Only an in-place upgrade needs this; a first install is handled by the # app:enable below. - name: run libresign migrations in debyltech-cloud become: true become_user: "{{ podman_user }}" ansible.builtin.command: > podman exec -u www-data debyltech-cloud php occ upgrade when: libresign_installed.rc == 0 - name: ensure libresign app is enabled in debyltech-cloud become: true become_user: "{{ podman_user }}" ansible.builtin.command: > podman exec -u www-data debyltech-cloud php occ app:enable libresign register: libresign_enable changed_when: "'already enabled' not in libresign_enable.stdout" # 14.2.x's downloader does not create its own target directories: on a fresh # appdata every java/pdftk download fails with "Directory ... does not exist # for sink value". Creating them first is harmless once they exist. - name: pre-create libresign binary directories in debyltech-cloud become: true become_user: "{{ podman_user }}" changed_when: false ansible.builtin.command: > podman exec -u www-data debyltech-cloud sh -c 'd=$(ls -d /var/www/html/data/appdata_*/libresign) && mkdir -p "$d/x86_64/linux/java" "$d/x86_64/pdftk"' # "Finished with success" is printed even when every download failed, so this # check only catches the command itself falling over. The real gate is the # configure:check verify task below, which hashes each binary against the # release's signed metadata. - name: install libresign java/pdftk/jsignpdf binaries in debyltech-cloud become: true become_user: "{{ podman_user }}" ansible.builtin.command: > podman exec -u www-data debyltech-cloud php occ libresign:install --java --pdftk --jsignpdf register: libresign_install changed_when: false failed_when: "'Finished with success' not in libresign_install.stdout" - name: check whether libresign root certificate is configured become: true become_user: "{{ podman_user }}" ansible.builtin.command: > podman exec -u www-data debyltech-cloud php occ libresign:configure:check --certificate register: libresign_cert_check changed_when: false failed_when: false # Guarded: re-running would mint a new root CA and orphan every certificate # already issued. No --ou -- see skudak/cloud.yml. - name: generate libresign root certificate for debyltech-cloud become: true become_user: "{{ podman_user }}" ansible.builtin.command: > podman exec -u www-data debyltech-cloud php occ libresign:configure:openssl --cn="{{ libresign_debyltech_cert_cn }}" -o "{{ libresign_debyltech_cert_o }}" -c "{{ libresign_debyltech_cert_c }}" -s "{{ libresign_debyltech_cert_st }}" -l "{{ libresign_debyltech_cert_l }}" when: "'error' in libresign_cert_check.stdout" changed_when: true # Signers are mostly customers WITHOUT an account, reached by emailed # invitation; the ID-document gate would leave them unable to sign at all. - name: relax libresign identification-document gate in debyltech-cloud become: true become_user: "{{ podman_user }}" ansible.builtin.command: > podman exec -u www-data debyltech-cloud php occ config:app:set libresign identification_documents --value=0 register: libresign_ident changed_when: "'is now set to' in libresign_ident.stdout" # Must be exactly GRAPHIC_ONLY -- see skudak/cloud.yml. - name: use signature-only stamp in debyltech-cloud libresign become: true become_user: "{{ podman_user }}" ansible.builtin.command: > podman exec -u www-data debyltech-cloud php occ config:app:set libresign signature_render_mode --value=GRAPHIC_ONLY register: libresign_render changed_when: "'is now set to' in libresign_render.stdout" # Lets account-owned emails be added as signers. NEVER set the _email variant # of this key to 'no' -- see skudak/cloud.yml. - name: allow account-owned emails as libresign signers in debyltech-cloud become: true become_user: "{{ podman_user }}" ansible.builtin.command: > podman exec -u www-data debyltech-cloud php occ config:app:set core shareapi_restrict_user_enumeration_full_match --value=no register: debyltech_enum_fullmatch changed_when: "'is now set to' in debyltech_enum_fullmatch.stdout" # Settings Skudak only ever had from clicks in the LibreSign admin page, never # in git -- a fresh instance without them cannot invite anyone by address: # # identify_methods The EMAIL identification method. Without it the signer # search only lists accounts, so an outside address # returns a bare "No signers." -- the whole point of this # instance. clickToSign (no emailed code) and # can_create_account=false, as on Skudak: the emailed link # is the identity check, and customers never get accounts. # signature_background_type=deleted # Drops the LibreSign logo watermark from behind the # stamp, so with GRAPHIC_ONLY the stamp is the drawn mark # and nothing else. # collect_metadata Records signer IP/user agent alongside each signature. - name: set libresign signer identification and stamp settings in debyltech-cloud become: true become_user: "{{ podman_user }}" ansible.builtin.command: > podman exec -u www-data debyltech-cloud php occ config:app:set libresign {{ item.k }} --value={{ item.v | quote }} register: debyltech_libresign_settings changed_when: "'is now set to' in debyltech_libresign_settings.stdout" loop: - k: identify_methods v: >- {{ [{'name': 'email', 'friendly_name': 'Email', 'enabled': true, 'mandatory': true, 'signatureMethods': { 'clickToSign': {'name': 'clickToSign', 'enabled': true}, 'emailToken': {'name': 'emailToken', 'enabled': false}}, 'can_create_account': false, 'test_url': '/index.php/settings/admin/mailtest', 'signatureMethodEnabled': 'clickToSign'}] | to_json }} - {k: signature_background_type, v: deleted} - {k: collect_metadata, v: "1"} loop_control: label: "{{ item.k }}" # The validation footer ("Digitally signed by ... Validate in ") is WANTED # -- only its QR code goes, below. FooterHandler defaults add_footer to true # when unset, but the 14.2 admin page renders unset as UNCHECKED, inviting # someone to "correct" it into actually turning the footer off. Stored # explicitly so the page shows what the code does. - name: keep libresign validation footer text in debyltech-cloud become: true become_user: "{{ podman_user }}" ansible.builtin.command: > podman exec -u www-data debyltech-cloud php occ config:app:set libresign add_footer --value=1 --type=boolean register: libresign_footer changed_when: "'is now set to' in libresign_footer.stdout" - name: drop libresign validation QR code from signed-PDF footer in debyltech-cloud become: true become_user: "{{ podman_user }}" ansible.builtin.command: > podman exec -u www-data debyltech-cloud php occ config:app:set libresign write_qrcode_on_footer --value=0 --type=boolean register: libresign_qr changed_when: "'is now set to' in libresign_qr.stdout" - name: verify libresign configuration in debyltech-cloud become: true become_user: "{{ podman_user }}" ansible.builtin.command: > podman exec -u www-data debyltech-cloud php occ libresign:configure:check register: libresign_verify changed_when: false # Double backslashes: Jinja unescapes string literals, so a single '\b' # becomes a BACKSPACE character and this could never match -- which is # how a check reporting three errors passed clean on 2026-09-28. failed_when: libresign_verify.stdout is search('\\berror\\b') # --------------------------------------------------------------------------- # Background jobs. A fresh install defaults to AJAX mode, which only runs jobs # while someone has the web UI open -- LibreSign's queued signature mail and # every cleanup job would stall. The cloud-cron timer included below drives # cron.php; this tells Nextcloud to expect it. - name: set debyltech-cloud background jobs to cron become: true become_user: "{{ podman_user }}" ansible.builtin.command: > podman exec -u www-data debyltech-cloud php occ config:app:set core backgroundjobs_mode --value=cron register: debyltech_bgjobs changed_when: "'is now set to' in debyltech_bgjobs.stdout" - name: disable nextcloud signup link in debyltech-cloud config become: true ansible.builtin.lineinfile: path: "{{ cloud_debyltech_path }}/config/config.php" regexp: "^\\s*'simpleSignUpLink\\.shown'\\s*=>" line: " 'simpleSignUpLink.shown' => false," insertbefore: '^\);' create: false # --------------------------------------------------------------------------- # Branding: debyltechmail, cloned from skudakmail. custom_apps is a persisted # bind mount, so only enabling and config need reasserting. # Owned directly by the HOST uid that rootless podman maps www-data (33) to -- # subuid start + 32, since container uid 1 is the first subuid. Skudak copies # as the subuid and then `podman unshare chown`s, which flips ownership back # and forth so the copy reports changed on every run; here that would also # re-import the theming logos below every time. - name: deploy debyltechmail email-template app to debyltech-cloud become: true ansible.builtin.copy: src: debyltechmail/ dest: "{{ cloud_debyltech_path }}/apps/debyltechmail/" owner: "{{ podman_subuid.stdout | int + 32 }}" group: "{{ podman_subuid.stdout | int + 32 }}" mode: 0644 directory_mode: 0755 register: debyltechmail_copy notify: restorecon podman - name: enable debyltechmail app in debyltech-cloud become: true become_user: "{{ podman_user }}" ansible.builtin.command: > podman exec -u www-data debyltech-cloud php occ app:enable debyltechmail register: debyltechmail_enable changed_when: "'already enabled' not in debyltechmail_enable.stdout" # Behind rootless podman's port forwarder, every request -- Caddy's included -- # reaches Apache FROM THE CONTAINER'S OWN ADDRESS on `shared`, not from the # host. Unless exactly that address is a trusted proxy, Nextcloud ignores the # X-Forwarded-For header Caddy sends, so every client looks like one IP: # brute-force throttling then penalises everyone at once. Read per deploy # because the address is assigned at container creation, and deploys are the # only thing that recreate it. - name: read debyltech-cloud container address become: true become_user: "{{ podman_user }}" ansible.builtin.command: > podman inspect debyltech-cloud --format "{{ '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' }}" register: debyltech_cloud_ip changed_when: false failed_when: debyltech_cloud_ip.stdout is not match('^[0-9.]+$') # System config, set only when it differs so a clean re-deploy reports no # changes (Skudak's equivalents report changed on every run). Values are # single-quoted into the shell, so the backslashes in mail_template_class pass # through literally. overwrite.cli.url is what LibreSign invitation links and # mail asset URLs are built from when sent by a background job. - name: set debyltech-cloud system config become: true become_user: "{{ podman_user }}" ansible.builtin.shell: | set -o pipefail occ() { podman exec -u www-data debyltech-cloud php occ "$@"; } # An UNSET key prints nothing and exits 1 -- indistinguishable from "" # by output alone, which would skip setting an intentionally empty value. cur=$(occ config:system:get {{ item.k }}) || cur='' if [ "$cur" != {{ item.v | quote }} ]; then occ config:system:set {{ item.k }} --value={{ item.v | quote }} --type={{ item.t | default('string') }} >/dev/null echo CHANGED fi args: executable: /bin/bash register: debyltech_sysconfig changed_when: "'CHANGED' in debyltech_sysconfig.stdout" loop: - {k: overwrite.cli.url, v: "https://{{ cloud_debyltech_server_name }}"} - {k: overwriteprotocol, v: https} - {k: trusted_proxies 0, v: "{{ debyltech_cloud_ip.stdout }}"} # Hour in UTC: 05:00 UTC is 01:00/00:00 Eastern, ahead of the 04:15 backup. - {k: maintenance_window_start, v: "5", t: integer} - {k: default_phone_region, v: US} # New accounts -- customers above all -- start with an empty home rather # than Nextcloud's sample Manual/intro video/Readme and Templates folder. - {k: skeletondirectory, v: ""} - {k: templatedirectory, v: ""} - {k: loglevel, v: "2", t: integer} - {k: log_rotate_size, v: "10485760", t: integer} - {k: mail_template_class, v: "OCA\\Debyltechmail\\Mail\\DebyltechEMailTemplate"} - {k: mail_smtpmode, v: smtp} - {k: mail_smtphost, v: "{{ cloud_debyltech_smtp_host }}"} - {k: mail_smtpport, v: "{{ cloud_debyltech_smtp_port }}", t: integer} - {k: mail_smtpsecure, v: ssl} - {k: mail_smtpauth, v: "true", t: boolean} - {k: mail_from_address, v: noreply} - {k: mail_domain, v: debyltech.com} loop_control: label: "{{ item.k }}" - name: set debyltech-cloud SES SMTP credentials become: true become_user: "{{ podman_user }}" ansible.builtin.shell: | set -o pipefail occ() { podman exec -u www-data debyltech-cloud php occ "$@"; } cur=$(occ config:system:get {{ item.k }} || true) if [ "$cur" != {{ item.v | quote }} ]; then occ config:system:set {{ item.k }} --value={{ item.v | quote }} >/dev/null echo CHANGED fi args: executable: /bin/bash register: debyltech_smtp_creds changed_when: "'CHANGED' in debyltech_smtp_creds.stdout" loop: - {k: mail_smtpname, v: "{{ cloud_debyltech_smtp_user }}"} - {k: mail_smtppassword, v: "{{ cloud_debyltech_smtp_pass }}"} loop_control: label: "{{ item.k }}" no_log: true # Compared first: theming:config prints "Updated" even when nothing changed. - name: set debyltech-cloud theming become: true become_user: "{{ podman_user }}" ansible.builtin.shell: | set -o pipefail occ() { podman exec -u www-data debyltech-cloud php occ "$@"; } cur=$(occ config:app:get theming {{ item.k }} || true) if [ "$cur" != {{ item.v | quote }} ]; then occ theming:config {{ item.k }} {{ item.v | quote }} >/dev/null echo CHANGED fi args: executable: /bin/bash loop: - {k: name, v: "de Byl Technologies"} - {k: slogan, v: "Hardware, firmware and design services"} - {k: url, v: "https://debyltech.com"} - {k: primary_color, v: "{{ theming_debyltech_primary }}"} - {k: background_color, v: "{{ theming_debyltech_background }}"} register: debyltech_theming changed_when: "'CHANGED' in debyltech_theming.stdout" loop_control: label: "{{ item.k }}" # The web UI logos ship inside the debyltechmail app (the white variants; the # ink wordmark is the mail one). theming:config re-imports the file on every # call, so it runs only when the app's files changed or no logo is set yet. # `logo` is the wide wordmark on the login page; `logoheader` is the square # mark in the top bar, where a wordmark would shrink to illegibility. # Plain theming_debyltech_background instead of Nextcloud's stock blue-shapes # image. `background backgroundColor` is a special case in UpdateConfig.php # (absent from --help) that drops the image and sets backgroundMime, exactly # what the admin UI's "remove background image" does. - name: use a plain colour login background in debyltech-cloud become: true become_user: "{{ podman_user }}" ansible.builtin.shell: | set -o pipefail occ() { podman exec -u www-data debyltech-cloud php occ "$@"; } if [ "$(occ config:app:get theming backgroundMime || true)" != backgroundColor ]; then occ theming:config background backgroundColor >/dev/null echo CHANGED fi args: executable: /bin/bash register: debyltech_background changed_when: "'CHANGED' in debyltech_background.stdout" - name: check debyltech-cloud theming logos become: true become_user: "{{ podman_user }}" ansible.builtin.command: > podman exec -u www-data debyltech-cloud php occ config:app:get theming {{ item }}Mime loop: [logo, logoheader] register: debyltech_logo_mime changed_when: false failed_when: false - name: set debyltech-cloud theming logos become: true become_user: "{{ podman_user }}" ansible.builtin.command: > podman exec -u www-data debyltech-cloud php occ theming:config {{ item.item }} /var/www/html/custom_apps/debyltechmail/img/{{ logo_files[item.item] }} loop: "{{ debyltech_logo_mime.results }}" when: debyltechmail_copy is changed or item.rc != 0 or item.stdout == '' vars: logo_files: logo: debyltech-wordmark-white.png logoheader: debyltech-mark-white.png loop_control: label: "{{ item.item }}" # Fails the play if branding, the LibreSign settings above, or Redis locking # have silently regressed -- see skudak/cloud.yml. - name: template debyltechmail verification script become: true ansible.builtin.template: src: nextcloud/debyltechmail-verify.php.j2 dest: "{{ cloud_debyltech_path }}/scripts/debyltechmail-verify.php" owner: "{{ podman_subuid.stdout }}" group: "{{ podman_subuid.stdout }}" mode: 0644 notify: restorecon podman - name: verify debyltech mail branding is live become: true become_user: "{{ podman_user }}" ansible.builtin.shell: > set -o pipefail; podman exec -i -u www-data debyltech-cloud php < {{ cloud_debyltech_path }}/scripts/debyltechmail-verify.php args: executable: /bin/bash register: debyltechmail_verify changed_when: false - include_tasks: containers/cloud-cron.yml vars: cron_name: debyltech-cloud cron_container: debyltech-cloud cron_script_path: /usr/local/bin/debyltech-cloud-cron.sh # BUSINESS data that DELIBERATELY reaches personal storage -- the opposite of # Skudak, and on purpose: de Byl Technologies LLC is the owner's own company. # # Chain: this rsync -> TrueNAS /mnt/glacier/debyltechcloud (05:00 ZFS # snapshot) -> the personal "iDrive E2 Backup" cloud-sync task, which pushes # /mnt/glacier to the personal iDrive e2 bucket. Unlike /skudakcloud/**, # /skudakapps/** and /skudakgit/**, there is NO exclude for /debyltechcloud/** # on that task, and there must not be one -- that inclusion IS the offsite # copy. If that ever changes, give it its own cloud-sync task first. - include_tasks: containers/cloud-backup.yml vars: backup_name: debyltech-cloud data_path: "{{ cloud_debyltech_path }}/data" config_path: "{{ cloud_debyltech_path }}/config" db_container: debyltech-cloud-db ssh_key_path: /etc/ssh/backup_keys/debyltech-cloud ssh_key_content: "{{ cloud_debyltech_backup_ssh_key }}" ssh_user: debyltechcloud remote_path: /mnt/glacier/debyltechcloud script_path: /usr/local/bin/debyltech-cloud-backup.sh # data/ is mode 770 here too; see skudak/cloud.yml. backup_rsync_extra_args: "--chmod=Du=rwx,Dgo=rx" # Between the 04:00 personal and 04:30 Skudak runs, before the 05:00 # TrueNAS snapshot. backup_oncalendar: "*-*-* 04:15:00"