diff --git a/collabora/CHANGELOG.md b/collabora/CHANGELOG.md index d5851e8d77..e98698830f 100644 --- a/collabora/CHANGELOG.md +++ b/collabora/CHANGELOG.md @@ -1,5 +1,6 @@ ## 26.04.2.4.1 (2026-07-26) +- Rebuild on a Debian base: upstream turned collabora/code into a distroless image with no shell, which broke the addon build entirely. Collabora is now copied from the official image onto ghcr.io/hassio-addons/debian-base, and the addon ships its own launcher in place of the removed /start-collabora-online.sh - Fix version numbering: releases on CollaboraOnline/online are now Helm charts only, which had renumbered the addon from 25.4.9.2 down to 1.3.0 and hid updates. The version is tracked from the collabora/code Docker Hub tags again - `server_name` is now passed to Collabora, fixing `Your browser has been unable to connect to the Collabora server` behind a reverse proxy - `domain1` was never passed to Collabora at all (the script read a `domain` option that does not exist, and recent Collabora releases dropped that variable). It is now deprecated and applied as `server_name` diff --git a/collabora/Dockerfile b/collabora/Dockerfile index e6a80949e9..4f7517ff61 100644 --- a/collabora/Dockerfile +++ b/collabora/Dockerfile @@ -16,6 +16,23 @@ ARG BUILD_FROM ARG BUILD_VERSION + +############################################################################### +# Get Collabora Online from the official image +# +# Upstream rebuilt collabora/code as a Nix-based distroless image: /bin and +# /sbin are empty, so it can no longer be used as BUILD_FROM (s6, bashio and +# every RUN need a shell). Only the Collabora payload is taken from it, on top +# of a normal Debian base. +# +# Copy only what belongs to Collabora. Do NOT copy /etc or /nix: in that image +# /etc/resolv.conf, /etc/hosts, /etc/passwd, /etc/group and /etc/nsswitch.conf +# are symlinks into /nix/store, and importing them breaks DNS resolution and +# wipes the base image users. +############################################################################### +FROM collabora/code:latest AS collabora + +# hadolint ignore=DL3006 FROM ${BUILD_FROM} ################## @@ -55,12 +72,46 @@ COPY ha_automodules.sh /ha_automodules.sh RUN chmod 744 /ha_automodules.sh && /ha_automodules.sh "$MODULES" && rm /ha_automodules.sh # Manual apps -ENV PACKAGES="" +# coolwsd itself only needs glibc/libstdc++ (max GLIBCXX_3.4.22); the office +# engine bundles its own cairo, fontconfig, curl, icu and fonts under +# /opt/collaboraoffice/program. openssl is used to generate the self-signed +# certificate when the ssl option is off, cpio and findutils by the jail setup. +ENV PACKAGES="ca-certificates cpio findutils fontconfig libcap2-bin libstdc++6 openssl tzdata" # Automatic apps & bashio COPY ha_autoapps.sh /ha_autoapps.sh RUN chmod 744 /ha_autoapps.sh && /ha_autoapps.sh "$PACKAGES" || true && rm /ha_autoapps.sh +# Collabora Online payload, taken from the official image. COPY --from keeps the +# numeric ownership, so /opt/cool and /etc/coolwsd arrive already owned by 1001. +COPY --from=collabora /usr/bin/coolwsd /usr/bin/coolforkit-caps /usr/bin/coolforkit-ns /usr/bin/coolmount /usr/bin/ +COPY --from=collabora /usr/share/coolwsd /usr/share/coolwsd +COPY --from=collabora /etc/coolwsd /etc/coolwsd +COPY --from=collabora /opt/collaboraoffice /opt/collaboraoffice +COPY --from=collabora /opt/cool /opt/cool + +# Recreate the runtime user the official image declares (uid/gid 1001), and the +# per-container state upstream sets up in its own final build stage. +RUN \ + groupadd --system --gid 1001 cool && \ + useradd --system --uid 1001 --gid 1001 --home-dir /opt/cool --shell /usr/sbin/nologin cool && \ + mkdir -p /opt/cool/child-roots /opt/cool/cache && \ + chown -R 1001:1001 /opt/cool /etc/coolwsd && \ + chmod 640 /etc/coolwsd/coolwsd.xml && \ + touch /var/log/coolwsd.log && \ + chown 1001:1001 /var/log/coolwsd.log && \ + # the WOPI proof key must be unique per container, not baked into the image + rm -rf /etc/coolwsd/proof_key* && \ + fc-cache /opt/collaboraoffice/share/fonts/truetype > /dev/null 2>&1 || true + +# Fail the build rather than ship an image that cannot start: ha_autoapps.sh is +# invoked with "|| true", and coolwsd comes from an image built against a +# different libc, so both are worth proving here. +RUN \ + command -v openssl > /dev/null && \ + command -v su > /dev/null && \ + /usr/bin/coolwsd --version + ################ # 4 Entrypoint # ################ diff --git a/collabora/build.json b/collabora/build.json index f70552aa00..794de9e1ff 100644 --- a/collabora/build.json +++ b/collabora/build.json @@ -1,6 +1,6 @@ { "build_from": { - "aarch64": "collabora/code:latest-arm64", - "amd64": "collabora/code:latest-amd64" + "aarch64": "ghcr.io/hassio-addons/debian-base:9.3.0", + "amd64": "ghcr.io/hassio-addons/debian-base:9.3.0" } } diff --git a/collabora/rootfs/etc/cont-init.d/99-run.sh b/collabora/rootfs/etc/cont-init.d/99-run.sh index 2ccdf8594e..5b1522dd38 100755 --- a/collabora/rootfs/etc/cont-init.d/99-run.sh +++ b/collabora/rootfs/etc/cont-init.d/99-run.sh @@ -141,4 +141,9 @@ chown -R 1001 /etc/coolwsd chmod -R 755 /opt/cool/systemplate bashio::log.info "Starting Collabora Online..." -su -p -s /bin/bash "$(getent passwd 1001 | cut -d: -f1)" -c "/start-collabora-online.sh" +# coolwsd refuses to run as root. The official image used to ship +# /start-collabora-online.sh, which is gone since it became distroless, so the +# add-on provides its own launcher. It reads everything from the environment, +# which su -p preserves. +export HOME=/opt/cool +su -p -s /bin/bash cool -c /usr/local/bin/collabora-run.sh diff --git a/collabora/rootfs/usr/local/bin/collabora-run.sh b/collabora/rootfs/usr/local/bin/collabora-run.sh new file mode 100644 index 0000000000..a3264ebe11 --- /dev/null +++ b/collabora/rootfs/usr/local/bin/collabora-run.sh @@ -0,0 +1,55 @@ +#!/bin/bash +# shellcheck shell=bash +# +# Launch coolwsd. +# +# The official image used to ship /start-collabora-online.sh and set it as its +# entrypoint. Since the move to a distroless image that script is gone, so the +# add-on provides its own equivalent. It is invoked as uid 1001 by +# /etc/cont-init.d/99-run.sh and takes everything from the environment, which +# avoids re-quoting extra_params through su. +set -e + +# Collabora serves https itself unless the add-on already installed real +# certificates, in which case 99-run.sh exports DONT_GEN_SSL_CERT. +cert_params="" +if [ -z "${DONT_GEN_SSL_CERT:-}" ]; then + SSL_DIR="/tmp/ssl" + mkdir -p "${SSL_DIR}/certs/ca" "${SSL_DIR}/certs/servers/localhost" "${SSL_DIR}/certs/tmp" + + openssl genrsa -out "${SSL_DIR}/certs/ca/root.key.pem" 2048 + openssl req -x509 -new -nodes \ + -key "${SSL_DIR}/certs/ca/root.key.pem" -days 9131 \ + -out "${SSL_DIR}/certs/ca/root.crt.pem" \ + -subj "/C=DE/ST=BW/L=Stuttgart/O=Dummy Authority/CN=Dummy Authority" + + openssl genrsa -out "${SSL_DIR}/certs/servers/localhost/privkey.pem" 2048 + openssl req -new -sha256 \ + -key "${SSL_DIR}/certs/servers/localhost/privkey.pem" \ + -out "${SSL_DIR}/certs/tmp/localhost.csr.pem" \ + -subj "/C=DE/ST=BW/L=Stuttgart/O=Dummy Authority/CN=${cert_domain:-localhost}" + openssl x509 -req -days 9131 \ + -in "${SSL_DIR}/certs/tmp/localhost.csr.pem" \ + -CA "${SSL_DIR}/certs/ca/root.crt.pem" \ + -CAkey "${SSL_DIR}/certs/ca/root.key.pem" -CAcreateserial \ + -out "${SSL_DIR}/certs/servers/localhost/cert.pem" + + cert_params="--o:ssl.cert_file_path=${SSL_DIR}/certs/servers/localhost/cert.pem \ + --o:ssl.key_file_path=${SSL_DIR}/certs/servers/localhost/privkey.pem \ + --o:ssl.ca_file_path=${SSL_DIR}/certs/ca/root.crt.pem" +fi + +# Flags mirror the entrypoint of the official image. extra_params is expanded +# last so that add-on options and user overrides win. +# shellcheck disable=SC2086 +exec /usr/bin/coolwsd \ + --version \ + --use-env-vars \ + ${cert_params} \ + --o:sys_template_path=/opt/cool/systemplate \ + --o:child_root_path=/opt/cool/child-roots \ + --o:file_server_root_path=/usr/share/coolwsd \ + --o:cache_files.path=/opt/cool/cache \ + --o:logging.color=false \ + --o:stop_on_config_change=true \ + ${extra_params:-}