From 87cbdc05e3c0f77c9925586f695ed0e367e1a709 Mon Sep 17 00:00:00 2001 From: zerox80 Date: Fri, 10 Apr 2026 09:46:52 +0200 Subject: [PATCH 01/14] feat: add support for Euro Office integration with custom entrypoint and configuration --- .env.example | 26 + config/euro-office/app-registry.yaml | 71 ++ config/euro-office/entrypoint-override.sh | 142 ++++ .../euro-office/onlyoffice-docs-formats.json | 604 ++++++++++++++++++ config/opencloud/csp.yaml | 2 + external-proxy/euroffice-exposed.yml | 11 + external-proxy/euroffice.yml | 10 + traefik/euroffice.yml | 28 + weboffice/euroffice.yml | 82 +++ 9 files changed, 976 insertions(+) create mode 100644 config/euro-office/app-registry.yaml create mode 100644 config/euro-office/entrypoint-override.sh create mode 100644 config/euro-office/onlyoffice-docs-formats.json create mode 100644 external-proxy/euroffice-exposed.yml create mode 100644 external-proxy/euroffice.yml create mode 100644 traefik/euroffice.yml create mode 100644 weboffice/euroffice.yml diff --git a/.env.example b/.env.example index 4f59454..c1a4499 100644 --- a/.env.example +++ b/.env.example @@ -24,6 +24,14 @@ INSECURE=true #COMPOSE_FILE=docker-compose.yml:weboffice/collabora.yml:traefik/opencloud.yml:traefik/collabora.yml:idm/ldap-keycloak.yml:traefik/ldap-keycloak.yml # External IDP #COMPOSE_FILE=docker-compose.yml:weboffice/collabora.yml:traefik/opencloud.yml:traefik/collabora.yml:idm/external-idp.yml +# Euro Office with traefik and letsencrypt +#COMPOSE_FILE=docker-compose.yml:weboffice/euroffice.yml:traefik/opencloud.yml:traefik/euroffice.yml +# Euro Office with external proxy (Nginx, Caddy, etc.) +#COMPOSE_FILE=docker-compose.yml:weboffice/euroffice.yml:external-proxy/opencloud.yml:external-proxy/euroffice.yml +# Both Collabora and Euro Office with traefik +#COMPOSE_FILE=docker-compose.yml:weboffice/collabora.yml:weboffice/euroffice.yml:traefik/opencloud.yml:traefik/collabora.yml:traefik/euroffice.yml +# Both Collabora and Euro Office with external proxy +#COMPOSE_FILE=docker-compose.yml:weboffice/collabora.yml:weboffice/euroffice.yml:external-proxy/opencloud.yml:external-proxy/collabora.yml:external-proxy/euroffice.yml ## Traefik Settings ## # Note: Traefik is always enabled and can't be disabled. @@ -239,6 +247,24 @@ COLLABORA_SSL_VERIFICATION=false COLLABORA_HOME_MODE= +### Euro Office Settings ### +# Domain of Euro Office, where you can find the document server. +# Defaults to "euro-office.opencloud.test" +EURO_OFFICE_DOMAIN= +# Domain of the wopiserver which handles Euro Office. +# Defaults to "wopiserver-eo.opencloud.test" +EURO_OFFICE_WOPISERVER_DOMAIN= +# JWT Secret for Euro Office. IMPORTANT: Change this for production! +# Defaults to "changeme" +EURO_OFFICE_JWT_SECRET= +# Euro Office Docker image. +# Defaults to "ghcr.io/euro-office/documentserver" +EURO_OFFICE_DOCKER_IMAGE= +# Euro Office Docker tag. +# Defaults to "latest" +EURO_OFFICE_DOCKER_TAG= + + ### Virusscanner Settings ### # IMPORTANT: If you enable antivirus, you also MUST configure the START_ADDITIONAL_SERVICES # envvar in the OpenCloud Settings above by adding 'antivirus' to the list. diff --git a/config/euro-office/app-registry.yaml b/config/euro-office/app-registry.yaml new file mode 100644 index 0000000..65c0107 --- /dev/null +++ b/config/euro-office/app-registry.yaml @@ -0,0 +1,71 @@ +app_registry: + mimetypes: + - mime_type: application/pdf + extension: pdf + name: PDF + description: PDF document + icon: '' + default_app: '' + allow_creation: false + - mime_type: application/vnd.oasis.opendocument.text + extension: odt + name: OpenDocument + description: OpenDocument text document + icon: '' + default_app: Collabora + allow_creation: true + - mime_type: application/vnd.oasis.opendocument.spreadsheet + extension: ods + name: OpenSpreadsheet + description: OpenDocument spreadsheet document + icon: '' + default_app: Collabora + allow_creation: true + - mime_type: application/vnd.oasis.opendocument.presentation + extension: odp + name: OpenPresentation + description: OpenDocument presentation document + icon: '' + default_app: Collabora + - mime_type: application/vnd.oasis.opendocument.graphics + extension: odg + name: OpenGraphics + description: OpenDocument graphics document + icon: '' + default_app: Collabora + allow_creation: true + - mime_type: application/vnd.openxmlformats-officedocument.wordprocessingml.document + extension: docx + name: Microsoft Word + description: Microsoft Word document + icon: '' + default_app: Euro-Office + allow_creation: true + - mime_type: application/vnd.openxmlformats-officedocument.wordprocessingml.form + extension: docxf + name: Form Document + description: Form Document + icon: '' + default_app: Euro-Office + allow_creation: true + - mime_type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet + extension: xlsx + name: Microsoft Excel + description: Microsoft Excel document + icon: '' + default_app: Euro-Office + allow_creation: true + - mime_type: application/vnd.openxmlformats-officedocument.presentationml.presentation + extension: pptx + name: Microsoft PowerPoint + description: Microsoft PowerPoint document + icon: '' + default_app: Euro-Office + allow_creation: true + - mime_type: application/vnd.jupyter + extension: ipynb + name: Jupyter Notebook + description: Jupyter Notebook + icon: '' + default_app: '' + allow_creation: true diff --git a/config/euro-office/entrypoint-override.sh b/config/euro-office/entrypoint-override.sh new file mode 100644 index 0000000..a95ad6a --- /dev/null +++ b/config/euro-office/entrypoint-override.sh @@ -0,0 +1,142 @@ +#!/bin/sh + +update_welcome_page() { + WELCOME_PAGE="/var/www/onlyoffice/documentserver-example/welcome/docker.html" + EXAMPLE_DISABLED_PAGE="/var/www/onlyoffice/documentserver-example/welcome/example-disabled.html" + + # Replace systemctl placeholder (set at build time) with docker+supervisorctl equivalent + sed -i 's|sudo systemctl start ds-example|sudo docker exec $(sudo docker ps -q) supervisorctl start ds:example|g' \ + "$EXAMPLE_DISABLED_PAGE" + + if [ -e "$WELCOME_PAGE" ]; then + DOCKER_CONTAINER_ID=$(basename "$(cat /proc/1/cpuset 2>/dev/null)") + if [ "${#DOCKER_CONTAINER_ID}" -lt 12 ]; then + DOCKER_CONTAINER_ID=$(hostname) + fi + if [ "${#DOCKER_CONTAINER_ID}" -ge 12 ]; then + if command -v docker > /dev/null 2>&1; then + DOCKER_CONTAINER_NAME=$(docker inspect --format="{{.Name}}" "$DOCKER_CONTAINER_ID" | sed 's|^/||') + sed -i "s|\$(sudo docker ps -q)|${DOCKER_CONTAINER_NAME}|g" \ + "$WELCOME_PAGE" "$EXAMPLE_DISABLED_PAGE" + else + DOCKER_CONTAINER_SHORT=$(echo "$DOCKER_CONTAINER_ID" | cut -c1-12) + sed -i "s|\$(sudo docker ps -q)|${DOCKER_CONTAINER_SHORT}|g" \ + "$WELCOME_PAGE" "$EXAMPLE_DISABLED_PAGE" + fi + fi + fi +} + +# Create symlink for /config -> /etc/onlyoffice/documentserver so tools can find config +ln -sf /etc/onlyoffice/documentserver /config 2>/dev/null || true + +service postgresql start +runuser -u rabbitmq -- rabbitmq-server -detached +service redis-server start +service nginx start + +# Ensure the api.js.tpl template exists (required by documentserver-flush-cache.sh) +API_TPL="/var/www/onlyoffice/documentserver/web-apps/apps/api/documents/api.js.tpl" +if [ ! -f "$API_TPL" ] && [ -f "/var/www/onlyoffice/documentserver/web-apps/apps/api/documents/api.js" ]; then + cp /var/www/onlyoffice/documentserver/web-apps/apps/api/documents/api.js "$API_TPL" +fi + +# Generate all fonts (AllFonts.js, font_selection.bin, presentation themes) +/usr/bin/documentserver-generate-allfonts.sh + +CONFIG_FILE="$EO_CONF/local.json" + +jq_filter='.' + +if [ -n "$JWT_SECRET" ]; then + jq_filter="$jq_filter | .services.CoAuthoring.secret.browser.string = \$jwtSecret" + jq_filter="$jq_filter | .services.CoAuthoring.secret.inbox.string = \$jwtSecret" + jq_filter="$jq_filter | .services.CoAuthoring.secret.outbox.string = \$jwtSecret" + jq_filter="$jq_filter | .services.CoAuthoring.secret.session.string = \$jwtSecret" +fi + +[ -n "$DB_PASSWORD" ] && \ + jq_filter="$jq_filter | .services.CoAuthoring.sql.dbPass = \$dbPassword" + +if [ "${USE_UNAUTHORIZED_STORAGE}" = "true" ]; then + jq_filter="$jq_filter | .services.CoAuthoring.requestDefaults.rejectUnauthorized = false" +fi + +[ -n "$ALLOW_PRIVATE_IP_ADDRESS" ] && \ + jq_filter="$jq_filter | .services.CoAuthoring[\"request-filtering-agent\"].allowPrivateIPAddress = true" + +[ -n "$ALLOW_META_IP_ADDRESS" ] && \ + jq_filter="$jq_filter | .services.CoAuthoring[\"request-filtering-agent\"].allowMetaIPAddress = true" + +# ── WOPI configuration ───────────────────────────────────────────────── +WOPI_ENABLED=${WOPI_ENABLED:-false} +DATA_DIR="/var/www/onlyoffice/Data" +WOPI_PRIVATE_KEY="${DATA_DIR}/wopi_private.key" +WOPI_PUBLIC_KEY="${DATA_DIR}/wopi_public.key" + +mkdir -p "$DATA_DIR" + +if [ ! -f "$WOPI_PRIVATE_KEY" ]; then + echo -n "Generating WOPI private key..." + openssl genpkey -algorithm RSA -outform PEM -out "$WOPI_PRIVATE_KEY" >/dev/null 2>&1 + echo "Done" +fi + +if [ ! -f "$WOPI_PUBLIC_KEY" ]; then + echo -n "Generating WOPI public key..." + openssl rsa -RSAPublicKey_out -in "$WOPI_PRIVATE_KEY" \ + -outform "MS PUBLICKEYBLOB" -out "$WOPI_PUBLIC_KEY" >/dev/null 2>&1 + echo "Done" +fi + +WOPI_PRIVATE_KEY_CONTENT=$(cat "$WOPI_PRIVATE_KEY") +WOPI_PUBLIC_KEY_CONTENT=$(openssl base64 -in "$WOPI_PUBLIC_KEY" -A) +WOPI_MODULUS=$(openssl rsa -pubin -inform "MS PUBLICKEYBLOB" -modulus -noout \ + -in "$WOPI_PUBLIC_KEY" | sed 's/Modulus=//' | \ + python3 -c "import sys,binascii,base64; print(base64.b64encode(binascii.unhexlify(sys.stdin.read().strip())).decode())") + +WOPI_EXPONENT=$(openssl rsa -pubin -inform "MS PUBLICKEYBLOB" -text -noout \ + -in "$WOPI_PUBLIC_KEY" | grep -oP '(?<=Exponent: )\d+') + +jq_filter="$jq_filter | .wopi.enable = \$wopiEnabled" +jq_filter="$jq_filter | .wopi.privateKey = \$wopiPrivateKey" +jq_filter="$jq_filter | .wopi.privateKeyOld = \$wopiPrivateKey" +jq_filter="$jq_filter | .wopi.publicKey = \$wopiPublicKey" +jq_filter="$jq_filter | .wopi.publicKeyOld = \$wopiPublicKey" +jq_filter="$jq_filter | .wopi.modulus = \$wopiModulus" +jq_filter="$jq_filter | .wopi.modulusOld = \$wopiModulus" +jq_filter="$jq_filter | .wopi.exponent = (\$wopiExponent | tonumber)" +jq_filter="$jq_filter | .wopi.exponentOld = (\$wopiExponent | tonumber)" +# ── End WOPI configuration ───────────────────────────────────────────── + +if [ "$jq_filter" != "." ]; then + if [ "$WOPI_ENABLED" = "true" ]; then + WOPI_ENABLED_JQ="true" + else + WOPI_ENABLED_JQ="false" + fi + + jq \ + --arg jwtSecret "$JWT_SECRET" \ + --arg dbPassword "$DB_PASSWORD" \ + --argjson wopiEnabled "$WOPI_ENABLED_JQ" \ + --arg wopiPrivateKey "$WOPI_PRIVATE_KEY_CONTENT" \ + --arg wopiPublicKey "$WOPI_PUBLIC_KEY_CONTENT" \ + --arg wopiModulus "$WOPI_MODULUS" \ + --arg wopiExponent "$WOPI_EXPONENT" \ + "$jq_filter" \ + "$CONFIG_FILE" > "${CONFIG_FILE}.tmp" + + mv "${CONFIG_FILE}.tmp" "$CONFIG_FILE" +fi + +update_welcome_page + +enable_supervisor_program() { + sed -i 's/^autostart=false$/autostart=true/' "/etc/supervisor/conf.d/$1.conf" +} + +[ "${ADMINPANEL_ENABLED:-false}" = "true" ] && enable_supervisor_program ds-adminpanel +[ "${EXAMPLE_ENABLED:-false}" = "true" ] && enable_supervisor_program ds-example + +/usr/bin/supervisord diff --git a/config/euro-office/onlyoffice-docs-formats.json b/config/euro-office/onlyoffice-docs-formats.json new file mode 100644 index 0000000..75a0a9d --- /dev/null +++ b/config/euro-office/onlyoffice-docs-formats.json @@ -0,0 +1,604 @@ +[ + { + "name": "doc", + "type": "word", + "actions": ["view", "auto-convert"], + "convert": ["docx", "bmp", "docm", "dotm", "dotx", "epub", "fb2", "gif", "html", "jpg", "md", "odt", "ott", "pdf", "pdfa", "png", "rtf", "txt"], + "mime": ["application/msword"] + }, + { + "name": "docm", + "type": "word", + "actions": ["view", "edit", "review", "comment", "encrypt"], + "convert": ["docx", "bmp", "dotm", "dotx", "epub", "fb2", "gif", "html", "jpg", "md", "odt", "ott", "pdf", "pdfa", "png", "rtf", "txt"], + "mime": ["application/vnd.ms-word.document.macroenabled.12"] + }, + { + "name": "docx", + "type": "word", + "actions": ["view", "edit", "review", "comment", "encrypt"], + "convert": ["bmp", "docm", "dotm", "dotx", "epub", "fb2", "gif", "html", "jpg", "md", "odt", "ott", "pdf", "pdfa", "png", "rtf", "txt"], + "mime": ["application/vnd.openxmlformats-officedocument.wordprocessingml.document"] + }, + { + "name": "dot", + "type": "word", + "actions": ["view", "auto-convert"], + "convert": ["docx", "bmp", "docm", "dotm", "dotx", "epub", "fb2", "gif", "html", "jpg", "md", "odt", "ott", "pdf", "pdfa", "png", "rtf", "txt"], + "mime": ["application/msword"] + }, + { + "name": "dotm", + "type": "word", + "actions": ["view", "edit", "review", "comment", "encrypt"], + "convert": ["docx", "bmp", "docm", "dotx", "epub", "fb2", "gif", "html", "jpg", "md", "odt", "ott", "pdf", "pdfa", "png", "rtf", "txt"], + "mime": ["application/vnd.ms-word.template.macroenabled.12"] + }, + { + "name": "dotx", + "type": "word", + "actions": ["view", "edit", "review", "comment", "encrypt"], + "convert": ["docx", "bmp", "docm", "dotm", "epub", "fb2", "gif", "html", "jpg", "md", "odt", "ott", "pdf", "pdfa", "png", "rtf", "txt"], + "mime": ["application/vnd.openxmlformats-officedocument.wordprocessingml.template"] + }, + { + "name": "epub", + "type": "word", + "actions": ["view", "lossy-edit", "auto-convert"], + "convert":["docx", "bmp", "docm", "dotm", "dotx", "fb2", "gif", "html", "jpg", "md", "odt", "ott", "pdf", "pdfa", "png", "rtf", "txt"], + "mime": ["application/epub+zip"] + }, + { + "name": "fb2", + "type": "word", + "actions": ["view", "lossy-edit", "auto-convert"], + "convert": ["docx", "bmp", "docm", "dotm", "dotx", "epub", "gif", "html", "jpg", "md", "odt", "ott", "pdf", "pdfa", "png", "rtf", "txt"], + "mime": ["text/fb2+xml", "application/x-fictionbook+xml"] + }, + { + "name": "fodt", + "type": "word", + "actions": ["view", "auto-convert"], + "convert": ["docx", "bmp", "docm", "dotm", "dotx", "epub", "fb2", "gif", "html", "jpg", "md", "odt", "ott", "pdf", "pdfa", "png", "rtf", "txt"], + "mime": ["application/vnd.oasis.opendocument.text-flat-xml"] + }, + { + "name": "gdoc", + "type": "word", + "actions": ["view"], + "convert": [], + "mime": ["application/vnd.google-apps.document"] + }, + { + "name": "hml", + "type": "word", + "actions": ["view", "auto-convert"], + "convert": ["docx", "bmp", "docm", "dotm", "dotx", "epub", "fb2", "gif", "html", "jpg", "md", "odt", "ott", "pdf", "pdfa", "png", "rtf", "txt"], + "mime": ["multipart/related"] + }, + { + "name": "htm", + "type": "word", + "actions": ["view", "auto-convert"], + "convert": ["docx", "bmp", "docm", "dotm", "dotx", "epub", "fb2", "gif", "jpg", "md", "odt", "ott", "pdf", "pdfa", "png", "rtf", "txt"], + "mime": ["text/html"] + }, + { + "name": "html", + "type": "word", + "actions": ["view", "lossy-edit", "auto-convert"], + "convert": ["docx", "bmp", "docm", "dotm", "dotx", "epub", "fb2", "gif", "jpg", "md", "odt", "ott", "pdf", "pdfa", "png", "rtf", "txt"], + "mime": ["text/html"] + }, + { + "name": "hwp", + "type": "word", + "actions": ["view", "auto-convert"], + "convert": ["docx", "bmp", "docm", "dotm", "dotx", "epub", "fb2", "gif", "html", "jpg", "md", "odt", "ott", "pdf", "pdfa", "png", "rtf", "txt"], + "mime": ["application/x-hwp", "application/x-hwp-v5"] + }, + { + "name": "hwpx", + "type": "word", + "actions": ["view", "auto-convert"], + "convert": ["docx", "bmp", "docm", "dotm", "dotx", "epub", "fb2", "gif", "html", "jpg", "md", "odt", "ott", "pdf", "pdfa", "png", "rtf", "txt"], + "mime": ["application/x-hwpx"] + }, + { + "name": "md", + "type": "word", + "actions": ["view", "auto-convert"], + "convert": ["docx", "bmp", "docm", "dotm", "dotx", "epub", "fb2", "gif", "html", "jpg", "odt", "ott", "pdf", "pdfa", "png", "rtf", "txt"], + "mime": ["text/markdown"] + }, + { + "name": "mht", + "type": "word", + "actions": ["view", "auto-convert"], + "convert": ["docx", "bmp", "docm", "dotm", "dotx", "epub", "fb2", "gif", "html", "jpg", "md", "odt", "ott", "pdf", "pdfa", "png", "rtf", "txt"], + "mime": ["message/rfc822"] + }, + { + "name": "mhtml", + "type": "word", + "actions": ["view", "auto-convert"], + "convert": ["docx", "bmp", "docm", "dotm", "dotx", "epub", "fb2", "gif", "html", "jpg", "md", "odt", "ott", "pdf", "pdfa", "png", "rtf", "txt"], + "mime": ["message/rfc822"] + }, + { + "name": "odt", + "type": "word", + "actions": ["view", "lossy-edit", "auto-convert", "review", "comment", "encrypt"], + "convert": ["docx", "bmp", "docm", "dotm", "dotx", "epub", "fb2", "gif", "html", "jpg", "md", "ott", "pdf", "pdfa", "png", "rtf", "txt"], + "mime": ["application/vnd.oasis.opendocument.text"] + }, + { + "name": "ott", + "type": "word", + "actions": ["view", "lossy-edit", "auto-convert", "review", "comment", "encrypt"], + "convert": ["docx", "bmp", "docm", "dotm", "dotx", "epub", "fb2", "gif", "html", "jpg", "md", "odt", "pdf", "pdfa", "png", "rtf", "txt"], + "mime": ["application/vnd.oasis.opendocument.text-template"] + }, + { + "name": "pages", + "type": "word", + "actions": ["view", "auto-convert"], + "convert": ["docx", "bmp", "docm", "dotm", "dotx", "epub", "fb2", "gif", "html", "jpg", "md", "odt", "ott", "pdf", "pdfa", "png", "rtf", "txt"], + "mime": ["application/vnd.apple.pages", "application/x-iwork-pages-sffpages"] + }, + { + "name": "rtf", + "type": "word", + "actions": ["view", "lossy-edit", "auto-convert", "review", "comment"], + "convert": ["docx", "bmp", "docm", "dotm", "dotx", "epub", "fb2", "gif", "html", "jpg", "md", "odt", "ott", "pdf", "pdfa", "png", "txt"], + "mime": ["application/rtf", "text/rtf"] + }, + { + "name": "stw", + "type": "word", + "actions": ["view", "auto-convert"], + "convert": ["docx", "bmp", "docm", "dotm", "dotx", "epub", "fb2", "gif", "html", "jpg", "md", "odt", "ott", "pdf", "pdfa", "png", "rtf", "txt"], + "mime": ["application/vnd.sun.xml.writer.template"] + }, + { + "name": "sxw", + "type": "word", + "actions": ["view", "auto-convert"], + "convert": ["docx", "bmp", "docm", "dotm", "dotx", "epub", "fb2", "gif", "html", "jpg", "md", "odt", "ott", "pdf", "pdfa", "png", "rtf", "txt"], + "mime": ["application/vnd.sun.xml.writer"] + }, + { + "name": "txt", + "type": "word", + "actions": ["view", "lossy-edit"], + "convert": ["docx", "bmp", "docm", "dotm", "dotx", "epub", "fb2", "gif", "html", "jpg", "md", "odt", "ott", "pdf", "pdfa", "png", "rtf"], + "mime": ["text/plain"] + }, + { + "name": "wps", + "type": "word", + "actions": ["view", "auto-convert"], + "convert": ["docx", "bmp", "docm", "dotm", "dotx", "epub", "fb2", "gif", "html", "jpg", "md", "odt", "ott", "pdf", "pdfa", "png", "rtf", "txt"], + "mime": ["application/vnd.ms-works"] + }, + { + "name": "wpt", + "type": "word", + "actions": ["view", "auto-convert"], + "convert": ["docx", "bmp", "docm", "dotm", "dotx", "epub", "fb2", "gif", "html", "jpg", "md", "odt", "ott", "pdf", "pdfa", "png", "rtf", "txt"], + "mime": [] + }, + { + "name": "xml", + "type": "word", + "actions": ["view", "auto-convert"], + "convert": ["docx", "xlsx", "bmp", "csv", "docm", "dotm", "dotx", "epub", "fb2", "gif", "html", "jpg", "md", "ods", "odt", "ots", "ott", "pdf", "pdfa", "png", "rtf", "txt", "tsv", "xlsm", "xltm", "xltx"], + "mime": ["application/xml", "text/xml"] + }, + { + "name": "csv", + "type": "cell", + "actions": ["view", "lossy-edit", "customfilter"], + "convert": ["xlsx", "bmp", "gif", "jpg", "ods", "ots", "pdf", "pdfa", "png", "tsv", "xlsm", "xltm", "xltx"], + "mime": ["text/csv", "application/csv", "text/x-comma-separated-values", "text/x-csv"] + }, + { + "name": "et", + "type": "cell", + "actions": ["view", "auto-convert"], + "convert": ["xlsx", "bmp", "csv", "gif", "jpg", "ods", "ots", "pdf", "pdfa", "png", "tsv", "xlsm", "xltm", "xltx"], + "mime": [] + }, + { + "name": "ett", + "type": "cell", + "actions": ["view", "auto-convert"], + "convert": ["xlsx", "bmp", "csv", "gif", "jpg", "ods", "ots", "pdf", "pdfa", "png", "tsv", "xlsm", "xltm", "xltx"], + "mime": [] + }, + { + "name": "fods", + "type": "cell", + "actions": ["view", "auto-convert"], + "convert": ["xlsx", "bmp", "csv", "gif", "jpg", "ods", "ots", "pdf", "pdfa", "png", "tsv", "xlsm", "xltm", "xltx"], + "mime": ["application/vnd.oasis.opendocument.spreadsheet-flat-xml"] + }, + { + "name": "gsheet", + "type": "cell", + "actions": ["view"], + "convert": [], + "mime": ["application/vnd.google-apps.spreadsheet"] + }, + { + "name": "numbers", + "type": "cell", + "actions": ["view", "auto-convert"], + "convert": ["xlsx", "bmp", "csv", "gif", "jpg", "ods", "ots", "pdf", "pdfa", "png", "tsv", "xlsm", "xltm", "xltx"], + "mime": ["application/vnd.apple.numbers", "application/x-iwork-numbers-sffnumbers"] + }, + { + "name": "ods", + "type": "cell", + "actions": ["view", "lossy-edit", "auto-convert", "customfilter", "comment", "encrypt"], + "convert": ["xlsx", "bmp", "csv", "gif", "jpg", "ots", "pdf", "pdfa", "png", "tsv", "xlsm", "xltm", "xltx"], + "mime": ["application/vnd.oasis.opendocument.spreadsheet"] + }, + { + "name": "ots", + "type": "cell", + "actions": ["view", "lossy-edit", "auto-convert", "customfilter", "comment", "encrypt"], + "convert": ["xlsx", "bmp", "csv", "gif", "jpg", "ods", "pdf", "pdfa", "png", "tsv", "tsv", "xlsm", "xltm", "xltx"], + "mime": ["application/vnd.oasis.opendocument.spreadsheet-template"] + }, + { + "name": "tsv", + "type": "cell", + "actions": ["view", "lossy-edit", "customfilter"], + "convert": ["xlsx", "bmp", "csv", "gif", "jpg", "ods", "ots", "pdf", "pdfa", "png", "xlsm", "xltm", "xltx"], + "mime": ["text/tab-separated-values"] + }, + { + "name": "sxc", + "type": "cell", + "actions": ["view", "auto-convert"], + "convert": ["xlsx", "bmp", "csv", "gif", "jpg", "ods", "ots", "pdf", "pdfa", "png", "tsv", "xlsm", "xltm", "xltx"], + "mime": ["application/vnd.sun.xml.calc"] + }, + { + "name": "xls", + "type": "cell", + "actions": ["view", "auto-convert"], + "convert": ["xlsx", "bmp", "csv", "gif", "jpg", "ods", "ots", "pdf", "pdfa", "png", "tsv", "xlsm", "xltm", "xltx"], + "mime": ["application/vnd.ms-excel"] + }, + { + "name": "xlsb", + "type": "cell", + "actions": ["view", "edit", "customfilter", "comment", "encrypt"], + "convert": ["xlsx", "bmp", "csv", "gif", "jpg", "ods", "ots", "pdf", "pdfa", "png", "tsv", "xlsm", "xltm", "xltx"], + "mime": ["application/vnd.ms-excel.sheet.binary.macroenabled.12"] + }, + { + "name": "xlsm", + "type": "cell", + "actions": ["view", "edit", "customfilter", "comment", "encrypt"], + "convert": ["xlsx", "bmp", "csv", "gif", "jpg", "ods", "ots", "pdf", "pdfa", "png", "tsv", "xltm", "xltx"], + "mime": ["application/vnd.ms-excel.sheet.macroenabled.12", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"] + }, + { + "name": "xlsx", + "type": "cell", + "actions": ["view", "edit", "customfilter", "comment", "encrypt"], + "convert": ["bmp", "csv", "gif", "jpg", "ods", "ots", "pdf", "pdfa", "png", "tsv", "xlsm", "xltm", "xltx"], + "mime": ["application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"] + }, + { + "name": "xlt", + "type": "cell", + "actions": ["view", "auto-convert"], + "convert": ["xlsx", "bmp", "csv", "gif", "jpg", "ods", "ots", "pdf", "pdfa", "png", "tsv", "xlsm", "xltm", "xltx"], + "mime": ["application/vnd.ms-excel"] + }, + { + "name": "xltm", + "type": "cell", + "actions": ["view", "edit", "customfilter", "comment", "encrypt"], + "convert": ["xlsx", "bmp", "csv", "gif", "jpg", "ods", "ots", "pdf", "pdfa", "png", "tsv", "xlsm", "xltx"], + "mime": ["application/vnd.ms-excel.template.macroenabled.12"] + }, + { + "name": "xltx", + "type": "cell", + "actions": ["view", "edit", "customfilter", "comment", "encrypt"], + "convert": ["xlsx", "bmp", "csv", "gif", "jpg", "ods", "ots", "pdf", "pdfa", "png", "tsv", "xlsm", "xltm"], + "mime": ["application/vnd.openxmlformats-officedocument.spreadsheetml.template"] + }, + { + "name": "dps", + "type": "slide", + "actions": ["view", "auto-convert"], + "convert": ["pptx", "bmp", "gif", "jpg", "odp", "otp", "pdf", "pdfa", "png", "potm", "potx", "ppsm", "ppsx", "pptm"], + "mime": [] + }, + { + "name": "dpt", + "type": "slide", + "actions": ["view", "auto-convert"], + "convert": ["pptx", "bmp", "gif", "jpg", "odp", "otp", "pdf", "pdfa", "png", "potm", "potx", "ppsm", "ppsx", "pptm"], + "mime": [] + }, + { + "name": "fodp", + "type": "slide", + "actions": ["view", "auto-convert"], + "convert": ["pptx", "bmp", "gif", "jpg", "odp", "otp", "pdf", "pdfa", "png", "potm", "potx", "ppsm", "ppsx", "pptm"], + "mime": ["application/vnd.oasis.opendocument.presentation-flat-xml"] + }, + { + "name": "gslides", + "type": "slide", + "actions": ["view"], + "convert": [], + "mime": ["application/vnd.google-apps.presentation"] + }, + { + "name": "key", + "type": "slide", + "actions": ["view", "auto-convert"], + "convert": ["pptx", "bmp", "gif", "jpg", "odp", "otp", "pdf", "pdfa", "png", "potm", "potx", "ppsm", "ppsx", "pptm", "txt"], + "mime": ["application/vnd.apple.keynote", "application/x-iwork-keynote-sffkey", "application/vnd.apple.keynote.13"] + }, + { + "name": "odg", + "type": "slide", + "actions": ["view", "auto-convert"], + "convert": ["pptx", "bmp", "gif", "jpg", "odp", "otp", "pdf", "pdfa", "png", "potm", "potx", "ppsm", "ppsx", "pptm", "txt"], + "mime": ["application/vnd.oasis.opendocument.graphics", "application/x-vnd.oasis.opendocument.graphics"] + }, + { + "name": "odp", + "type": "slide", + "actions": ["view", "lossy-edit", "auto-convert", "comment", "encrypt"], + "convert": ["pptx", "bmp", "gif", "jpg", "otp", "pdf", "pdfa", "png", "potm", "potx", "ppsm", "ppsx", "pptm", "txt"], + "mime": ["application/vnd.oasis.opendocument.presentation"] + }, + { + "name": "otp", + "type": "slide", + "actions": ["view", "lossy-edit", "auto-convert", "comment", "encrypt"], + "convert": ["pptx", "bmp", "gif", "jpg", "odp", "pdf", "pdfa", "png", "potm", "potx", "ppsm", "ppsx", "pptm", "txt"], + "mime": ["application/vnd.oasis.opendocument.presentation-template"] + }, + { + "name": "pot", + "type": "slide", + "actions": ["view", "auto-convert"], + "convert": ["pptx", "bmp", "gif", "jpg", "odp", "otp", "pdf", "pdfa", "png", "potm", "potx", "ppsm", "ppsx", "pptm", "txt"], + "mime": ["application/vnd.ms-powerpoint"] + }, + { + "name": "potm", + "type": "slide", + "actions": ["view", "edit", "comment", "encrypt"], + "convert": ["pptx", "bmp", "gif", "jpg", "odp", "otp", "pdf", "pdfa", "png", "potx", "ppsm", "ppsx", "pptm", "txt"], + "mime": ["application/vnd.ms-powerpoint.template.macroenabled.12"] + }, + { + "name": "potx", + "type": "slide", + "actions": ["view", "edit", "comment", "encrypt"], + "convert": ["pptx", "bmp", "gif", "jpg", "odp", "otp", "pdf", "pdfa", "png", "potm", "ppsm", "ppsx", "pptm", "txt"], + "mime": ["application/vnd.openxmlformats-officedocument.presentationml.template"] + }, + { + "name": "pps", + "type": "slide", + "actions": ["view", "auto-convert"], + "convert": ["pptx", "bmp", "gif", "jpg", "odp", "otp", "pdf", "pdfa", "png", "potm", "potx", "ppsm", "ppsx", "pptm", "txt"], + "mime": ["application/vnd.ms-powerpoint"] + }, + { + "name": "ppsm", + "type": "slide", + "actions": ["view", "edit", "comment", "encrypt"], + "convert": ["pptx", "bmp", "gif", "jpg", "odp", "otp", "pdf", "pdfa", "png", "potm", "potx", "ppsx", "pptm", "txt"], + "mime": ["application/vnd.ms-powerpoint.slideshow.macroenabled.12"] + }, + { + "name": "ppsx", + "type": "slide", + "actions": ["view", "edit", "comment", "encrypt"], + "convert": ["pptx", "bmp", "gif", "jpg", "odp", "otp", "pdf", "pdfa", "png", "potm", "potx", "ppsm", "pptm", "txt"], + "mime": ["application/vnd.openxmlformats-officedocument.presentationml.slideshow"] + }, + { + "name": "ppt", + "type": "slide", + "actions": ["view", "auto-convert"], + "convert": ["pptx", "bmp", "gif", "jpg", "odp", "otp", "pdf", "pdfa", "png", "potm", "potx", "ppsm", "ppsx", "pptm", "txt"], + "mime": ["application/vnd.ms-powerpoint"] + }, + { + "name": "pptm", + "type": "slide", + "actions": ["view", "edit", "comment", "encrypt"], + "convert": ["pptx", "bmp", "gif", "jpg", "odp", "otp", "pdf", "pdfa", "png", "potm", "potx", "ppsm", "ppsx", "txt"], + "mime": ["application/vnd.ms-powerpoint.presentation.macroenabled.12"] + }, + { + "name": "pptx", + "type": "slide", + "actions": ["view", "edit", "comment", "encrypt"], + "convert": ["bmp", "gif", "jpg", "odp", "otp", "pdf", "pdfa", "png", "potm", "potx", "ppsm", "ppsx", "pptm", "txt"], + "mime": ["application/vnd.openxmlformats-officedocument.presentationml.presentation"] + }, + { + "name": "sxi", + "type": "slide", + "actions": ["view", "auto-convert"], + "convert": ["pptx", "bmp", "gif", "jpg", "odp", "otp", "pdf", "pdfa", "png", "potm", "potx", "ppsm", "ppsx", "pptm", "txt"], + "mime": ["application/vnd.sun.xml.impress"] + }, + { + "name": "djvu", + "type": "pdf", + "actions": ["view"], + "convert": ["bmp", "gif", "jpg", "pdf", "pdfa", "png"], + "mime": ["image/vnd.djvu"] + }, + { + "name": "docxf", + "type": "pdf", + "actions": ["view"], + "convert": ["docx", "bmp", "docm", "dotm", "dotx", "epub", "fb2", "gif", "html", "jpg", "md", "odt", "ott", "pdf", "pdfa", "png", "rtf", "txt"], + "mime": ["application/vnd.openxmlformats-officedocument.wordprocessingml.document.docxf"] + }, + { + "name": "oform", + "type": "pdf", + "actions": ["view"], + "convert": ["pdf"], + "mime": ["application/vnd.openxmlformats-officedocument.wordprocessingml.document.oform"] + }, + { + "name": "oxps", + "type": "pdf", + "actions": ["view"], + "convert": ["docx", "bmp", "docm", "dotm", "dotx", "epub", "fb2", "gif", "html", "jpg", "md", "odt", "ott", "pdf", "pdfa", "png", "rtf", "txt"], + "mime": ["application/oxps"] + }, + { + "name": "pdf", + "type": "pdf", + "actions": ["view", "edit", "comment", "fill", "encrypt"], + "convert": ["docx", "bmp", "docm", "dotm", "dotx", "epub", "fb2", "gif", "html", "jpg", "md", "odt", "ott", "pdfa", "png", "rtf", "txt"], + "mime": ["application/pdf", "application/acrobat", "application/nappdf", "application/x-pdf", "image/pdf"] + }, + { + "name": "xps", + "type": "pdf", + "actions": ["view"], + "convert": ["docx", "bmp", "docm", "dotm", "dotx", "epub", "fb2", "gif", "html", "jpg", "md", "odt", "ott", "pdf", "pdfa", "png", "rtf", "txt"], + "mime": ["application/vnd.ms-xpsdocument", "application/xps"] + }, + { + "name": "vsdx", + "type": "diagram", + "actions": ["view"], + "convert": ["bmp", "gif", "jpg", "pdf", "pdfa", "png"], + "mime": ["application/vnd.ms-visio.drawing, application/vnd.visio2013", "application/vnd.visio"] + }, + { + "name": "vsdm", + "type": "diagram", + "actions": ["view"], + "convert": ["bmp", "gif", "jpg", "pdf", "pdfa", "png"], + "mime": ["application/vnd.ms-visio.drawing.macroEnabled.12"] + }, + { + "name": "vssm", + "type": "diagram", + "actions": ["view"], + "convert": ["bmp", "gif", "jpg", "pdf", "pdfa", "png"], + "mime": ["application/vnd.ms-visio.stencil.macroEnabled.12"] + }, + { + "name": "vssx", + "type": "diagram", + "actions": ["view"], + "convert": ["bmp", "gif", "jpg", "pdf", "pdfa", "png"], + "mime": ["application/vnd.ms-visio.stencil"] + }, + { + "name": "vstm", + "type": "diagram", + "actions": ["view"], + "convert": ["bmp", "gif", "jpg", "pdf", "pdfa", "png"], + "mime": ["application/vnd.ms-visio.template.macroEnabled.12"] + }, + { + "name": "vstx", + "type": "diagram", + "actions": ["view"], + "convert": ["bmp", "gif", "jpg", "pdf", "pdfa", "png"], + "mime": ["application/vnd.ms-visio.template"] + }, + { + "name": "bmp", + "type": "", + "actions": [], + "convert": [], + "mime": ["image/bmp"] + }, + { + "name": "gif", + "type": "", + "actions": [], + "convert": [], + "mime": ["image/gif"] + }, + { + "name": "heic", + "type": "", + "actions": [], + "convert": [], + "mime": ["image/heic"] + }, + { + "name": "heif", + "type": "", + "actions": [], + "convert": [], + "mime": ["image/heif"] + }, + { + "name": "jpg", + "type": "", + "actions": [], + "convert": [], + "mime": ["image/jpeg"] + }, + { + "name": "pdfa", + "type": "", + "actions": [], + "convert": [], + "mime": ["application/pdf", "application/acrobat", "application/nappdf", "application/x-pdf", "image/pdf"] + }, + { + "name": "png", + "type": "", + "actions": [], + "convert": [], + "mime": ["image/png"] + }, + { + "name": "tif", + "type": "", + "actions": [], + "convert": [], + "mime": ["image/tif", "image/x-tif", "application/tif", "application/x-tif"] + }, + { + "name": "tiff", + "type": "", + "actions": [], + "convert": [], + "mime": ["image/tiff", "image/x-tiff", "application/tiff", "application/x-tiff"] + }, + { + "name": "webp", + "type": "", + "actions": [], + "convert": [], + "mime": ["image/webp"] + }, + { + "name": "zip", + "type": "", + "actions": [], + "convert": [], + "mime": ["application/zip"] + } +] diff --git a/config/opencloud/csp.yaml b/config/opencloud/csp.yaml index cde4b1e..cf6f528 100644 --- a/config/opencloud/csp.yaml +++ b/config/opencloud/csp.yaml @@ -21,6 +21,7 @@ directives: - 'https://embed.diagrams.net/' # In contrary to bash and docker the default is given after the | character - 'https://${COLLABORA_DOMAIN|collabora.opencloud.test}${TRAEFIK_PORT_HTTPS}/' + - 'https://${EURO_OFFICE_DOMAIN|euro-office.opencloud.test}${TRAEFIK_PORT_HTTPS}/' # This is needed for the external-sites web extension when embedding sites - 'https://docs.opencloud.eu' img-src: @@ -31,6 +32,7 @@ directives: - 'https://tile.openstreetmap.org/' # In contrary to bash and docker the default is given after the | character - 'https://${COLLABORA_DOMAIN|collabora.opencloud.test}${TRAEFIK_PORT_HTTPS}/' + - 'https://${EURO_OFFICE_DOMAIN|euro-office.opencloud.test}${TRAEFIK_PORT_HTTPS}/' manifest-src: - '''self''' media-src: diff --git a/external-proxy/euroffice-exposed.yml b/external-proxy/euroffice-exposed.yml new file mode 100644 index 0000000..ff50034 --- /dev/null +++ b/external-proxy/euroffice-exposed.yml @@ -0,0 +1,11 @@ +--- +# only expose the ports when you know what you are doing! +services: + collaboration-eo: + ports: + # expose the euro-office wopi server on all interfaces + - "0.0.0.0:9302:9300" + euro-office: + ports: + # expose the euro-office document server on all interfaces + - "0.0.0.0:9900:80" diff --git a/external-proxy/euroffice.yml b/external-proxy/euroffice.yml new file mode 100644 index 0000000..6b344c4 --- /dev/null +++ b/external-proxy/euroffice.yml @@ -0,0 +1,10 @@ +--- +services: + collaboration-eo: + ports: + # expose the euro-office wopi server on localhost + - "127.0.0.1:9302:9300" + euro-office: + ports: + # expose the euro-office document server on localhost + - "127.0.0.1:9900:80" diff --git a/traefik/euroffice.yml b/traefik/euroffice.yml new file mode 100644 index 0000000..ea4795c --- /dev/null +++ b/traefik/euroffice.yml @@ -0,0 +1,28 @@ +--- +services: + traefik: + networks: + opencloud-net: + aliases: + - ${EURO_OFFICE_DOMAIN:-euro-office.opencloud.test} + - ${EURO_OFFICE_WOPISERVER_DOMAIN:-wopiserver-eo.opencloud.test} + collaboration-eo: + labels: + - "traefik.enable=true" + - "traefik.http.routers.collaboration-eo.entrypoints=https" + - "traefik.http.routers.collaboration-eo.rule=Host(`${EURO_OFFICE_WOPISERVER_DOMAIN:-wopiserver-eo.opencloud.test}`)" + - "traefik.http.routers.collaboration-eo.${TRAEFIK_SERVICES_TLS_CONFIG}" + - "traefik.http.routers.collaboration-eo.service=collaboration-eo" + - "traefik.http.routers.collaboration-eo.middlewares=hsts-header" + - "traefik.http.services.collaboration-eo.loadbalancer.server.port=9300" + euro-office: + labels: + - "traefik.enable=true" + - "traefik.http.routers.euro-office.entrypoints=https" + - "traefik.http.routers.euro-office.rule=Host(`${EURO_OFFICE_DOMAIN:-euro-office.opencloud.test}`)" + - "traefik.http.routers.euro-office.${TRAEFIK_SERVICES_TLS_CONFIG}" + - "traefik.http.routers.euro-office.service=euro-office" + - "traefik.http.services.euro-office.loadbalancer.server.port=80" + # websockets can't be opened when this is omitted + - "traefik.http.middlewares.euro-office.headers.customrequestheaders.X-Forwarded-Proto=https" + - "traefik.http.routers.euro-office.middlewares=euro-office" diff --git a/weboffice/euroffice.yml b/weboffice/euroffice.yml new file mode 100644 index 0000000..e8da97a --- /dev/null +++ b/weboffice/euroffice.yml @@ -0,0 +1,82 @@ +--- +services: + + opencloud: + environment: + # this is needed for setting the correct CSP header + ONLYOFFICE_DOMAIN: ${EURO_OFFICE_DOMAIN:-euro-office.opencloud.test} + TRAEFIK_PORT_HTTPS: ${TRAEFIK_PORT_HTTPS:+:}${TRAEFIK_PORT_HTTPS:-} + # expose nats and the reva gateway for the collaboration service + NATS_NATS_HOST: 0.0.0.0 + GATEWAY_GRPC_ADDR: 0.0.0.0:9142 + volumes: + - ./config/euro-office/app-registry.yaml:/etc/opencloud/app-registry.yaml + + collaboration-eo: + # renovate: depName=opencloudeu/opencloud-rolling + image: ${OC_DOCKER_IMAGE:-opencloudeu/opencloud-rolling}:${OC_DOCKER_TAG:-6.0.0} + user: ${OC_CONTAINER_UID_GID:-1000:1000} + networks: + opencloud-net: + depends_on: + opencloud: + condition: service_started + euro-office: + condition: service_healthy + entrypoint: + - /bin/sh + command: [ "-c", "opencloud collaboration server" ] + environment: + COLLABORATION_GRPC_ADDR: 0.0.0.0:9301 + COLLABORATION_HTTP_ADDR: 0.0.0.0:9300 + MICRO_REGISTRY: "nats-js-kv" + MICRO_REGISTRY_ADDRESS: "opencloud:9233" + COLLABORATION_WOPI_SRC: https://${EURO_OFFICE_WOPISERVER_DOMAIN:-wopiserver-eo.opencloud.test}${TRAEFIK_PORT_HTTPS:+:}${TRAEFIK_PORT_HTTPS:-} + COLLABORATION_APP_NAME: "Euro-Office" + COLLABORATION_APP_PRODUCT: "OnlyOffice" + COLLABORATION_SERVICE_NAME: "collaboration-eo" + COLLABORATION_APP_ADDR: https://${EURO_OFFICE_DOMAIN:-euro-office.opencloud.test}${TRAEFIK_PORT_HTTPS:+:}${TRAEFIK_PORT_HTTPS:-} + COLLABORATION_APP_ICON: https://${EURO_OFFICE_DOMAIN:-euro-office.opencloud.test}${TRAEFIK_PORT_HTTPS:+:}${TRAEFIK_PORT_HTTPS:-}/web-apps/apps/documenteditor/main/resources/img/favicon.ico + COLLABORATION_APP_INSECURE: "${INSECURE:-true}" + COLLABORATION_CS3API_DATAGATEWAY_INSECURE: "${INSECURE:-true}" + COLLABORATION_APP_PROOF_DISABLE: "true" + COLLABORATION_LOG_LEVEL: ${LOG_LEVEL:-info} + OC_URL: https://${OC_DOMAIN:-cloud.opencloud.test}${TRAEFIK_PORT_HTTPS:+:}${TRAEFIK_PORT_HTTPS:-} + volumes: + # configure the .env file to use own paths instead of docker internal volumes + - ${OC_CONFIG_DIR:-opencloud-config}:/etc/opencloud + logging: + driver: ${LOG_DRIVER:-local} + restart: always + + euro-office: + image: ${EURO_OFFICE_DOCKER_IMAGE:-ghcr.io/euro-office/documentserver}:${EURO_OFFICE_DOCKER_TAG:-latest} + # changelog https://github.com/EURO-office/DocumentServer/releases + networks: + opencloud-net: + entrypoint: + - /bin/sh + - /entrypoint-override.sh + environment: + WOPI_ENABLED: "true" + JWT_SECRET: "${EURO_OFFICE_JWT_SECRET:-changeme}" + # self-signed certificates + USE_UNAUTHORIZED_STORAGE: "${INSECURE:-false}" + volumes: + - ./config/euro-office/entrypoint-override.sh:/entrypoint-override.sh + - ./config/euro-office/onlyoffice-docs-formats.json:/var/www/onlyoffice/documentserver/document-formats/onlyoffice-docs-formats.json + logging: + driver: ${LOG_DRIVER:-local} + restart: always + healthcheck: + test: + [ + "CMD", + "bash", + "-c", + "exec 3<>/dev/tcp/127.0.0.1/80 && printf 'GET /hosting/discovery HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n' >&3 && cat <&3 | head -1 | grep -q '200 OK'" + ] + interval: 30s + timeout: 10s + retries: 5 + start_period: 120s From f01a8969bf3ad1589b64246c4284b71764c4f1ec Mon Sep 17 00:00:00 2001 From: zerox80 Date: Fri, 10 Apr 2026 10:18:41 +0200 Subject: [PATCH 02/14] feat: add docker-compose configuration for Euro-Office integration --- weboffice/euroffice.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/weboffice/euroffice.yml b/weboffice/euroffice.yml index e8da97a..14ffe1f 100644 --- a/weboffice/euroffice.yml +++ b/weboffice/euroffice.yml @@ -4,7 +4,7 @@ services: opencloud: environment: # this is needed for setting the correct CSP header - ONLYOFFICE_DOMAIN: ${EURO_OFFICE_DOMAIN:-euro-office.opencloud.test} + EURO_OFFICE_DOMAIN: ${EURO_OFFICE_DOMAIN:-euro-office.opencloud.test} TRAEFIK_PORT_HTTPS: ${TRAEFIK_PORT_HTTPS:+:}${TRAEFIK_PORT_HTTPS:-} # expose nats and the reva gateway for the collaboration service NATS_NATS_HOST: 0.0.0.0 From b5eb7bb7ca69739dc890b5f034ca831a10621840 Mon Sep 17 00:00:00 2001 From: zerox80 Date: Mon, 20 Apr 2026 13:36:03 +0200 Subject: [PATCH 03/14] refactor: standardize service names and update port configurations for Euro Office integration --- .env.example | 7 -- config/euro-office/entrypoint-override.sh | 142 ---------------------- external-proxy/euroffice-exposed.yml | 6 +- external-proxy/euroffice.yml | 6 +- traefik/euroffice.yml | 16 +-- weboffice/euroffice.yml | 9 +- 6 files changed, 16 insertions(+), 170 deletions(-) delete mode 100644 config/euro-office/entrypoint-override.sh diff --git a/.env.example b/.env.example index c1a4499..5c687dc 100644 --- a/.env.example +++ b/.env.example @@ -28,10 +28,6 @@ INSECURE=true #COMPOSE_FILE=docker-compose.yml:weboffice/euroffice.yml:traefik/opencloud.yml:traefik/euroffice.yml # Euro Office with external proxy (Nginx, Caddy, etc.) #COMPOSE_FILE=docker-compose.yml:weboffice/euroffice.yml:external-proxy/opencloud.yml:external-proxy/euroffice.yml -# Both Collabora and Euro Office with traefik -#COMPOSE_FILE=docker-compose.yml:weboffice/collabora.yml:weboffice/euroffice.yml:traefik/opencloud.yml:traefik/collabora.yml:traefik/euroffice.yml -# Both Collabora and Euro Office with external proxy -#COMPOSE_FILE=docker-compose.yml:weboffice/collabora.yml:weboffice/euroffice.yml:external-proxy/opencloud.yml:external-proxy/collabora.yml:external-proxy/euroffice.yml ## Traefik Settings ## # Note: Traefik is always enabled and can't be disabled. @@ -251,9 +247,6 @@ COLLABORA_HOME_MODE= # Domain of Euro Office, where you can find the document server. # Defaults to "euro-office.opencloud.test" EURO_OFFICE_DOMAIN= -# Domain of the wopiserver which handles Euro Office. -# Defaults to "wopiserver-eo.opencloud.test" -EURO_OFFICE_WOPISERVER_DOMAIN= # JWT Secret for Euro Office. IMPORTANT: Change this for production! # Defaults to "changeme" EURO_OFFICE_JWT_SECRET= diff --git a/config/euro-office/entrypoint-override.sh b/config/euro-office/entrypoint-override.sh deleted file mode 100644 index a95ad6a..0000000 --- a/config/euro-office/entrypoint-override.sh +++ /dev/null @@ -1,142 +0,0 @@ -#!/bin/sh - -update_welcome_page() { - WELCOME_PAGE="/var/www/onlyoffice/documentserver-example/welcome/docker.html" - EXAMPLE_DISABLED_PAGE="/var/www/onlyoffice/documentserver-example/welcome/example-disabled.html" - - # Replace systemctl placeholder (set at build time) with docker+supervisorctl equivalent - sed -i 's|sudo systemctl start ds-example|sudo docker exec $(sudo docker ps -q) supervisorctl start ds:example|g' \ - "$EXAMPLE_DISABLED_PAGE" - - if [ -e "$WELCOME_PAGE" ]; then - DOCKER_CONTAINER_ID=$(basename "$(cat /proc/1/cpuset 2>/dev/null)") - if [ "${#DOCKER_CONTAINER_ID}" -lt 12 ]; then - DOCKER_CONTAINER_ID=$(hostname) - fi - if [ "${#DOCKER_CONTAINER_ID}" -ge 12 ]; then - if command -v docker > /dev/null 2>&1; then - DOCKER_CONTAINER_NAME=$(docker inspect --format="{{.Name}}" "$DOCKER_CONTAINER_ID" | sed 's|^/||') - sed -i "s|\$(sudo docker ps -q)|${DOCKER_CONTAINER_NAME}|g" \ - "$WELCOME_PAGE" "$EXAMPLE_DISABLED_PAGE" - else - DOCKER_CONTAINER_SHORT=$(echo "$DOCKER_CONTAINER_ID" | cut -c1-12) - sed -i "s|\$(sudo docker ps -q)|${DOCKER_CONTAINER_SHORT}|g" \ - "$WELCOME_PAGE" "$EXAMPLE_DISABLED_PAGE" - fi - fi - fi -} - -# Create symlink for /config -> /etc/onlyoffice/documentserver so tools can find config -ln -sf /etc/onlyoffice/documentserver /config 2>/dev/null || true - -service postgresql start -runuser -u rabbitmq -- rabbitmq-server -detached -service redis-server start -service nginx start - -# Ensure the api.js.tpl template exists (required by documentserver-flush-cache.sh) -API_TPL="/var/www/onlyoffice/documentserver/web-apps/apps/api/documents/api.js.tpl" -if [ ! -f "$API_TPL" ] && [ -f "/var/www/onlyoffice/documentserver/web-apps/apps/api/documents/api.js" ]; then - cp /var/www/onlyoffice/documentserver/web-apps/apps/api/documents/api.js "$API_TPL" -fi - -# Generate all fonts (AllFonts.js, font_selection.bin, presentation themes) -/usr/bin/documentserver-generate-allfonts.sh - -CONFIG_FILE="$EO_CONF/local.json" - -jq_filter='.' - -if [ -n "$JWT_SECRET" ]; then - jq_filter="$jq_filter | .services.CoAuthoring.secret.browser.string = \$jwtSecret" - jq_filter="$jq_filter | .services.CoAuthoring.secret.inbox.string = \$jwtSecret" - jq_filter="$jq_filter | .services.CoAuthoring.secret.outbox.string = \$jwtSecret" - jq_filter="$jq_filter | .services.CoAuthoring.secret.session.string = \$jwtSecret" -fi - -[ -n "$DB_PASSWORD" ] && \ - jq_filter="$jq_filter | .services.CoAuthoring.sql.dbPass = \$dbPassword" - -if [ "${USE_UNAUTHORIZED_STORAGE}" = "true" ]; then - jq_filter="$jq_filter | .services.CoAuthoring.requestDefaults.rejectUnauthorized = false" -fi - -[ -n "$ALLOW_PRIVATE_IP_ADDRESS" ] && \ - jq_filter="$jq_filter | .services.CoAuthoring[\"request-filtering-agent\"].allowPrivateIPAddress = true" - -[ -n "$ALLOW_META_IP_ADDRESS" ] && \ - jq_filter="$jq_filter | .services.CoAuthoring[\"request-filtering-agent\"].allowMetaIPAddress = true" - -# ── WOPI configuration ───────────────────────────────────────────────── -WOPI_ENABLED=${WOPI_ENABLED:-false} -DATA_DIR="/var/www/onlyoffice/Data" -WOPI_PRIVATE_KEY="${DATA_DIR}/wopi_private.key" -WOPI_PUBLIC_KEY="${DATA_DIR}/wopi_public.key" - -mkdir -p "$DATA_DIR" - -if [ ! -f "$WOPI_PRIVATE_KEY" ]; then - echo -n "Generating WOPI private key..." - openssl genpkey -algorithm RSA -outform PEM -out "$WOPI_PRIVATE_KEY" >/dev/null 2>&1 - echo "Done" -fi - -if [ ! -f "$WOPI_PUBLIC_KEY" ]; then - echo -n "Generating WOPI public key..." - openssl rsa -RSAPublicKey_out -in "$WOPI_PRIVATE_KEY" \ - -outform "MS PUBLICKEYBLOB" -out "$WOPI_PUBLIC_KEY" >/dev/null 2>&1 - echo "Done" -fi - -WOPI_PRIVATE_KEY_CONTENT=$(cat "$WOPI_PRIVATE_KEY") -WOPI_PUBLIC_KEY_CONTENT=$(openssl base64 -in "$WOPI_PUBLIC_KEY" -A) -WOPI_MODULUS=$(openssl rsa -pubin -inform "MS PUBLICKEYBLOB" -modulus -noout \ - -in "$WOPI_PUBLIC_KEY" | sed 's/Modulus=//' | \ - python3 -c "import sys,binascii,base64; print(base64.b64encode(binascii.unhexlify(sys.stdin.read().strip())).decode())") - -WOPI_EXPONENT=$(openssl rsa -pubin -inform "MS PUBLICKEYBLOB" -text -noout \ - -in "$WOPI_PUBLIC_KEY" | grep -oP '(?<=Exponent: )\d+') - -jq_filter="$jq_filter | .wopi.enable = \$wopiEnabled" -jq_filter="$jq_filter | .wopi.privateKey = \$wopiPrivateKey" -jq_filter="$jq_filter | .wopi.privateKeyOld = \$wopiPrivateKey" -jq_filter="$jq_filter | .wopi.publicKey = \$wopiPublicKey" -jq_filter="$jq_filter | .wopi.publicKeyOld = \$wopiPublicKey" -jq_filter="$jq_filter | .wopi.modulus = \$wopiModulus" -jq_filter="$jq_filter | .wopi.modulusOld = \$wopiModulus" -jq_filter="$jq_filter | .wopi.exponent = (\$wopiExponent | tonumber)" -jq_filter="$jq_filter | .wopi.exponentOld = (\$wopiExponent | tonumber)" -# ── End WOPI configuration ───────────────────────────────────────────── - -if [ "$jq_filter" != "." ]; then - if [ "$WOPI_ENABLED" = "true" ]; then - WOPI_ENABLED_JQ="true" - else - WOPI_ENABLED_JQ="false" - fi - - jq \ - --arg jwtSecret "$JWT_SECRET" \ - --arg dbPassword "$DB_PASSWORD" \ - --argjson wopiEnabled "$WOPI_ENABLED_JQ" \ - --arg wopiPrivateKey "$WOPI_PRIVATE_KEY_CONTENT" \ - --arg wopiPublicKey "$WOPI_PUBLIC_KEY_CONTENT" \ - --arg wopiModulus "$WOPI_MODULUS" \ - --arg wopiExponent "$WOPI_EXPONENT" \ - "$jq_filter" \ - "$CONFIG_FILE" > "${CONFIG_FILE}.tmp" - - mv "${CONFIG_FILE}.tmp" "$CONFIG_FILE" -fi - -update_welcome_page - -enable_supervisor_program() { - sed -i 's/^autostart=false$/autostart=true/' "/etc/supervisor/conf.d/$1.conf" -} - -[ "${ADMINPANEL_ENABLED:-false}" = "true" ] && enable_supervisor_program ds-adminpanel -[ "${EXAMPLE_ENABLED:-false}" = "true" ] && enable_supervisor_program ds-example - -/usr/bin/supervisord diff --git a/external-proxy/euroffice-exposed.yml b/external-proxy/euroffice-exposed.yml index ff50034..69d56c6 100644 --- a/external-proxy/euroffice-exposed.yml +++ b/external-proxy/euroffice-exposed.yml @@ -1,10 +1,10 @@ --- # only expose the ports when you know what you are doing! services: - collaboration-eo: + collaboration: ports: - # expose the euro-office wopi server on all interfaces - - "0.0.0.0:9302:9300" + # expose the wopi server on all interfaces + - "0.0.0.0:9300:9300" euro-office: ports: # expose the euro-office document server on all interfaces diff --git a/external-proxy/euroffice.yml b/external-proxy/euroffice.yml index 6b344c4..6b64222 100644 --- a/external-proxy/euroffice.yml +++ b/external-proxy/euroffice.yml @@ -1,9 +1,9 @@ --- services: - collaboration-eo: + collaboration: ports: - # expose the euro-office wopi server on localhost - - "127.0.0.1:9302:9300" + # expose the wopi server on localhost + - "127.0.0.1:9300:9300" euro-office: ports: # expose the euro-office document server on localhost diff --git a/traefik/euroffice.yml b/traefik/euroffice.yml index ea4795c..60435f8 100644 --- a/traefik/euroffice.yml +++ b/traefik/euroffice.yml @@ -5,16 +5,16 @@ services: opencloud-net: aliases: - ${EURO_OFFICE_DOMAIN:-euro-office.opencloud.test} - - ${EURO_OFFICE_WOPISERVER_DOMAIN:-wopiserver-eo.opencloud.test} - collaboration-eo: + - ${WOPISERVER_DOMAIN:-wopiserver.opencloud.test} + collaboration: labels: - "traefik.enable=true" - - "traefik.http.routers.collaboration-eo.entrypoints=https" - - "traefik.http.routers.collaboration-eo.rule=Host(`${EURO_OFFICE_WOPISERVER_DOMAIN:-wopiserver-eo.opencloud.test}`)" - - "traefik.http.routers.collaboration-eo.${TRAEFIK_SERVICES_TLS_CONFIG}" - - "traefik.http.routers.collaboration-eo.service=collaboration-eo" - - "traefik.http.routers.collaboration-eo.middlewares=hsts-header" - - "traefik.http.services.collaboration-eo.loadbalancer.server.port=9300" + - "traefik.http.routers.collaboration.entrypoints=https" + - "traefik.http.routers.collaboration.rule=Host(`${WOPISERVER_DOMAIN:-wopiserver.opencloud.test}`)" + - "traefik.http.routers.collaboration.${TRAEFIK_SERVICES_TLS_CONFIG}" + - "traefik.http.routers.collaboration.service=collaboration" + - "traefik.http.routers.collaboration.middlewares=hsts-header" + - "traefik.http.services.collaboration.loadbalancer.server.port=9300" euro-office: labels: - "traefik.enable=true" diff --git a/weboffice/euroffice.yml b/weboffice/euroffice.yml index 14ffe1f..200918d 100644 --- a/weboffice/euroffice.yml +++ b/weboffice/euroffice.yml @@ -12,7 +12,7 @@ services: volumes: - ./config/euro-office/app-registry.yaml:/etc/opencloud/app-registry.yaml - collaboration-eo: + collaboration: # renovate: depName=opencloudeu/opencloud-rolling image: ${OC_DOCKER_IMAGE:-opencloudeu/opencloud-rolling}:${OC_DOCKER_TAG:-6.0.0} user: ${OC_CONTAINER_UID_GID:-1000:1000} @@ -31,10 +31,9 @@ services: COLLABORATION_HTTP_ADDR: 0.0.0.0:9300 MICRO_REGISTRY: "nats-js-kv" MICRO_REGISTRY_ADDRESS: "opencloud:9233" - COLLABORATION_WOPI_SRC: https://${EURO_OFFICE_WOPISERVER_DOMAIN:-wopiserver-eo.opencloud.test}${TRAEFIK_PORT_HTTPS:+:}${TRAEFIK_PORT_HTTPS:-} + COLLABORATION_WOPI_SRC: https://${WOPISERVER_DOMAIN:-wopiserver.opencloud.test}${TRAEFIK_PORT_HTTPS:+:}${TRAEFIK_PORT_HTTPS:-} COLLABORATION_APP_NAME: "Euro-Office" COLLABORATION_APP_PRODUCT: "OnlyOffice" - COLLABORATION_SERVICE_NAME: "collaboration-eo" COLLABORATION_APP_ADDR: https://${EURO_OFFICE_DOMAIN:-euro-office.opencloud.test}${TRAEFIK_PORT_HTTPS:+:}${TRAEFIK_PORT_HTTPS:-} COLLABORATION_APP_ICON: https://${EURO_OFFICE_DOMAIN:-euro-office.opencloud.test}${TRAEFIK_PORT_HTTPS:+:}${TRAEFIK_PORT_HTTPS:-}/web-apps/apps/documenteditor/main/resources/img/favicon.ico COLLABORATION_APP_INSECURE: "${INSECURE:-true}" @@ -54,16 +53,12 @@ services: # changelog https://github.com/EURO-office/DocumentServer/releases networks: opencloud-net: - entrypoint: - - /bin/sh - - /entrypoint-override.sh environment: WOPI_ENABLED: "true" JWT_SECRET: "${EURO_OFFICE_JWT_SECRET:-changeme}" # self-signed certificates USE_UNAUTHORIZED_STORAGE: "${INSECURE:-false}" volumes: - - ./config/euro-office/entrypoint-override.sh:/entrypoint-override.sh - ./config/euro-office/onlyoffice-docs-formats.json:/var/www/onlyoffice/documentserver/document-formats/onlyoffice-docs-formats.json logging: driver: ${LOG_DRIVER:-local} From 3813131dfd313fed0886b04c9e45deeb85d7e717 Mon Sep 17 00:00:00 2001 From: zerox80 Date: Mon, 20 Apr 2026 16:25:25 +0200 Subject: [PATCH 04/14] feat: add lightweight WOPI init script for Euro Office --- config/euro-office/init-wopi.sh | 55 +++++++++++++++++++++++++++++++++ weboffice/euroffice.yml | 4 +++ 2 files changed, 59 insertions(+) create mode 100644 config/euro-office/init-wopi.sh diff --git a/config/euro-office/init-wopi.sh b/config/euro-office/init-wopi.sh new file mode 100644 index 0000000..8893c35 --- /dev/null +++ b/config/euro-office/init-wopi.sh @@ -0,0 +1,55 @@ +#!/bin/sh +set -e + +CONFIG_FILE="/etc/onlyoffice/documentserver/local.json" +DATA_DIR="/var/www/onlyoffice/Data" +WOPI_PRIVATE_KEY="${DATA_DIR}/wopi_private.key" +WOPI_PUBLIC_KEY="${DATA_DIR}/wopi_public.key" + +if [ "${WOPI_ENABLED:-false}" = "true" ]; then + mkdir -p "$DATA_DIR" + + if [ ! -f "$WOPI_PRIVATE_KEY" ]; then + echo "Generating WOPI private key..." + openssl genpkey -algorithm RSA -outform PEM -out "$WOPI_PRIVATE_KEY" >/dev/null 2>&1 + fi + + if [ ! -f "$WOPI_PUBLIC_KEY" ]; then + echo "Generating WOPI public key..." + openssl rsa -RSAPublicKey_out -in "$WOPI_PRIVATE_KEY" \ + -outform "MS PUBLICKEYBLOB" -out "$WOPI_PUBLIC_KEY" >/dev/null 2>&1 + fi + + WOPI_PRIVATE_KEY_CONTENT=$(cat "$WOPI_PRIVATE_KEY") + WOPI_PUBLIC_KEY_CONTENT=$(openssl base64 -in "$WOPI_PUBLIC_KEY" -A) + WOPI_MODULUS=$(openssl rsa -pubin -inform "MS PUBLICKEYBLOB" -modulus -noout \ + -in "$WOPI_PUBLIC_KEY" | sed 's/Modulus=//' | \ + python3 -c "import sys,binascii,base64; print(base64.b64encode(binascii.unhexlify(sys.stdin.read().strip())).decode())") + + WOPI_EXPONENT=$(openssl rsa -pubin -inform "MS PUBLICKEYBLOB" -text -noout \ + -in "$WOPI_PUBLIC_KEY" | grep -oP '(?<=Exponent: )\d+') + + # Merge WOPI config into local.json + jq \ + --argjson wopiEnabled "true" \ + --arg wopiPrivateKey "$WOPI_PRIVATE_KEY_CONTENT" \ + --arg wopiPublicKey "$WOPI_PUBLIC_KEY_CONTENT" \ + --arg wopiModulus "$WOPI_MODULUS" \ + --arg wopiExponent "$WOPI_EXPONENT" \ + '.wopi.enable = $wopiEnabled | + .wopi.privateKey = $wopiPrivateKey | + .wopi.privateKeyOld = $wopiPrivateKey | + .wopi.publicKey = $wopiPublicKey | + .wopi.publicKeyOld = $wopiPublicKey | + .wopi.modulus = $wopiModulus | + .wopi.modulusOld = $wopiModulus | + .wopi.exponent = ($wopiExponent | tonumber) | + .wopi.exponentOld = ($wopiExponent | tonumber)' \ + "$CONFIG_FILE" > "${CONFIG_FILE}.tmp" + + mv "${CONFIG_FILE}.tmp" "$CONFIG_FILE" + echo "WOPI configuration injected successfully." +fi + +# Hand over to the official DocumentServer entrypoint +exec /entrypoint.sh "$@" diff --git a/weboffice/euroffice.yml b/weboffice/euroffice.yml index 200918d..803ed77 100644 --- a/weboffice/euroffice.yml +++ b/weboffice/euroffice.yml @@ -58,7 +58,11 @@ services: JWT_SECRET: "${EURO_OFFICE_JWT_SECRET:-changeme}" # self-signed certificates USE_UNAUTHORIZED_STORAGE: "${INSECURE:-false}" + entrypoint: + - /bin/sh + - /init-wopi.sh volumes: + - ./config/euro-office/init-wopi.sh:/init-wopi.sh:ro - ./config/euro-office/onlyoffice-docs-formats.json:/var/www/onlyoffice/documentserver/document-formats/onlyoffice-docs-formats.json logging: driver: ${LOG_DRIVER:-local} From 217099947fe1b9edcc0bbaff6ce3f005ea568a20 Mon Sep 17 00:00:00 2001 From: "v.scharf" Date: Tue, 16 Jun 2026 14:52:23 +0200 Subject: [PATCH 05/14] set OC_EVENTS_ENDPOINT for collaboration --- weboffice/collabora.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/weboffice/collabora.yml b/weboffice/collabora.yml index 431fa6d..35a8948 100644 --- a/weboffice/collabora.yml +++ b/weboffice/collabora.yml @@ -41,6 +41,7 @@ services: COLLABORATION_CS3API_DATAGATEWAY_INSECURE: "${INSECURE:-true}" COLLABORATION_LOG_LEVEL: ${LOG_LEVEL:-info} OC_URL: https://${OC_DOMAIN:-cloud.opencloud.test}${TRAEFIK_PORT_HTTPS:+:}${TRAEFIK_PORT_HTTPS:-} + OC_EVENTS_ENDPOINT: "opencloud:9233" volumes: # configure the .env file to use own paths instead of docker internal volumes - ${OC_CONFIG_DIR:-opencloud-config}:/etc/opencloud From 75941df4286f291292ac42cc8e2933b262eae298 Mon Sep 17 00:00:00 2001 From: Michael Barz Date: Wed, 17 Jun 2026 17:42:59 +0200 Subject: [PATCH 06/14] docs: add euro office --- README.md | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/README.md b/README.md index 7b35c0c..5c7fa14 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ OpenCloud Compose offers a modular approach to deploying OpenCloud with several - **Standard deployment** with Traefik reverse proxy and Let's Encrypt certificates or certificates from files - **External proxy** support for environments with existing reverse proxies (like Nginx, Caddy, etc.) - **Collabora Online** integration for document editing +- **Euro Office** integration for document editing - **Keycloak and LDAP** integration for centralized identity management - **Full text search** with Apache Tika for content extraction and metadata analysis - **Monitoring** with metrics endpoints for observability and performance monitoring @@ -107,6 +108,9 @@ This setup includes: ### With Collabora Online +> [!NOTE] +> Collabora Online and [Euro Office](#with-euro-office) are mutually exclusive web office backends — both use the same `collaboration` (WOPI) service. Enable only one of them at a time. + Include Collabora for document editing using either method: > **DNS Requirements**: This setup requires DNS entries for the main OpenCloud domain, Collabora subdomain, and WOPI server subdomain. Configure DNS A/AAAA records for your domains (e.g., `cloud.example.com`, `collabora.example.com`, `wopiserver.example.com`) or use a wildcard DNS entry (`*.example.com`). @@ -127,6 +131,34 @@ COMPOSE_FILE=docker-compose.yml:weboffice/collabora.yml:traefik/opencloud.yml:tr > 127.0.0.1 wopiserver.opencloud.test > ``` +### With Euro Office + +> [!NOTE] +> Euro Office and [Collabora Online](#with-collabora-online) are mutually exclusive web office backends — both use the same `collaboration` (WOPI) service. Enable only one of them at a time. + +Include Euro Office for document editing using either method: + +> **DNS Requirements**: This setup requires DNS entries for the main OpenCloud domain, Euro Office subdomain, and WOPI server subdomain. Configure DNS A/AAAA records for your domains (e.g., `cloud.example.com`, `euro-office.example.com`, `wopiserver.example.com`) or use a wildcard DNS entry (`*.example.com`). + +Using `-f` flags: +```bash +docker compose -f docker-compose.yml -f weboffice/euroffice.yml -f traefik/opencloud.yml -f traefik/euroffice.yml up -d +``` + +Or by setting in `.env`: +``` +COMPOSE_FILE=docker-compose.yml:weboffice/euroffice.yml:traefik/opencloud.yml:traefik/euroffice.yml +``` + +> **For local development only**: Add to `/etc/hosts`: +> ``` +> 127.0.0.1 euro-office.opencloud.test +> 127.0.0.1 wopiserver.opencloud.test +> ``` + +> [!IMPORTANT] +> Set a strong `EURO_OFFICE_JWT_SECRET` in your `.env` file for production. The default value (`changeme`) is intended for local development only. + ### With Full Text Search Enable full text search capabilities with Apache Tika using either method: @@ -228,6 +260,25 @@ This exposes the necessary ports: - Collabora: 9980 - WOPI server: 9300 +To use Euro Office instead of Collabora behind an external proxy, swap the web office compose files: + +```bash +docker compose -f docker-compose.yml -f weboffice/euroffice.yml -f external-proxy/opencloud.yml -f external-proxy/euroffice.yml up -d +``` + +Or by setting in `.env`: +``` +COMPOSE_FILE=docker-compose.yml:weboffice/euroffice.yml:external-proxy/opencloud.yml:external-proxy/euroffice.yml +``` + +This exposes the necessary ports: +- OpenCloud: 9200 +- Euro Office: 9900 +- WOPI server: 9300 + +> [!WARNING] +> `external-proxy/euroffice.yml` binds the exposed ports to `127.0.0.1` only. If your external proxy runs on a different host, use `external-proxy/euroffice-exposed.yml`, which binds to all interfaces (`0.0.0.0`). Only expose these ports when you know what you are doing. + **Please note:** If you're using **Nginx Proxy Manager (NPM)**, you **should NOT** activate **"Block Common Exploits"** for the Proxy Host. Otherwise, the desktop app authentication will return **error 403 Forbidden**. @@ -342,6 +393,10 @@ Key variables: | `INSECURE` | Skip certificate validation | true | | `COLLABORA_DOMAIN` | Collabora domain | collabora.opencloud.test | | `WOPISERVER_DOMAIN` | WOPI server domain | wopiserver.opencloud.test | +| `EURO_OFFICE_DOMAIN` | Euro Office document server domain | euro-office.opencloud.test | +| `EURO_OFFICE_JWT_SECRET` | JWT secret for Euro Office (change for production!) | changeme | +| `EURO_OFFICE_DOCKER_IMAGE` | Euro Office Docker image | ghcr.io/euro-office/documentserver | +| `EURO_OFFICE_DOCKER_TAG` | Euro Office Docker tag | latest | | `TIKA_IMAGE` | Apache Tika image tag | apache/tika:slim | | `KEYCLOAK_DOMAIN` | Keycloak domain | keycloak.opencloud.test | | `KEYCLOAK_ADMIN` | Keycloak admin username | kcadmin | From d853a5907865a2bc8f00a4d1ba248a4c406611b5 Mon Sep 17 00:00:00 2001 From: Alexander Ackermann Date: Thu, 18 Jun 2026 13:32:31 +0200 Subject: [PATCH 07/14] chore: bump collabora to 26.04.1.4.1 --- weboffice/collabora.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/weboffice/collabora.yml b/weboffice/collabora.yml index 35a8948..576dcaa 100644 --- a/weboffice/collabora.yml +++ b/weboffice/collabora.yml @@ -50,7 +50,7 @@ services: restart: always collabora: - image: collabora/code:25.04.10.3.1 + image: collabora/code:26.04.1.4.1 # release notes: https://www.collaboraonline.com/release-notes/ networks: opencloud-net: From 4531d137ef8980f616f66accb4aaf7ef8f61f39d Mon Sep 17 00:00:00 2001 From: cazo <79615454+Cassolette@users.noreply.github.com> Date: Thu, 18 Jun 2026 13:11:00 +0000 Subject: [PATCH 08/14] feat: system fonts to EO matching what was done for Collabora. --- weboffice/euroffice.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/weboffice/euroffice.yml b/weboffice/euroffice.yml index b302426..661000e 100644 --- a/weboffice/euroffice.yml +++ b/weboffice/euroffice.yml @@ -62,6 +62,9 @@ services: - /bin/sh - /init-wopi.sh volumes: + # Mount local TrueType fonts so the container can use system fonts + # (e.g. Microsoft fonts like Arial, Calibri, Cambria by installing the `ttf-mscorefonts-installer` package). + - /usr/share/fonts/truetype:/usr/share/fonts/truetype/more:ro - ./config/euro-office/init-wopi.sh:/init-wopi.sh:ro - ./config/euro-office/onlyoffice-docs-formats.json:/var/www/onlyoffice/documentserver/document-formats/onlyoffice-docs-formats.json logging: From 03ba22ed4e4809cc0d98ffdadec9aa93a2a1aa95 Mon Sep 17 00:00:00 2001 From: cazo <79615454+Cassolette@users.noreply.github.com> Date: Thu, 18 Jun 2026 13:24:23 +0000 Subject: [PATCH 09/14] fix: cleanup no longer required scripts WOPI fixes have been integrated into the docker image from v9.3.2-rc.1 onwards --- .gitattributes | 1 - config/euro-office/init-wopi.sh | 57 -- .../euro-office/onlyoffice-docs-formats.json | 604 ------------------ weboffice/euroffice.yml | 6 - 4 files changed, 668 deletions(-) delete mode 100644 .gitattributes delete mode 100644 config/euro-office/init-wopi.sh delete mode 100644 config/euro-office/onlyoffice-docs-formats.json diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index f1e639c..0000000 --- a/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -config/euro-office/init-wopi.sh text eol=lf diff --git a/config/euro-office/init-wopi.sh b/config/euro-office/init-wopi.sh deleted file mode 100644 index 5679a7f..0000000 --- a/config/euro-office/init-wopi.sh +++ /dev/null @@ -1,57 +0,0 @@ -#!/bin/sh -set -e - -CONFIG_FILE="/etc/onlyoffice/documentserver/local.json" -CONFIG_DIR="$(dirname "$CONFIG_FILE")" -DATA_DIR="/var/www/onlyoffice/Data" -WOPI_PRIVATE_KEY="${DATA_DIR}/wopi_private.key" -WOPI_PUBLIC_KEY="${DATA_DIR}/wopi_public.key" - -if [ "${WOPI_ENABLED:-false}" = "true" ]; then - mkdir -p "$CONFIG_DIR" "$DATA_DIR" - [ -f "$CONFIG_FILE" ] || echo '{}' > "$CONFIG_FILE" - - if [ ! -f "$WOPI_PRIVATE_KEY" ]; then - echo "Generating WOPI private key..." - openssl genpkey -algorithm RSA -outform PEM -out "$WOPI_PRIVATE_KEY" >/dev/null 2>&1 - fi - - if [ ! -f "$WOPI_PUBLIC_KEY" ]; then - echo "Generating WOPI public key..." - openssl rsa -RSAPublicKey_out -in "$WOPI_PRIVATE_KEY" \ - -outform "MS PUBLICKEYBLOB" -out "$WOPI_PUBLIC_KEY" >/dev/null 2>&1 - fi - - WOPI_PRIVATE_KEY_CONTENT=$(cat "$WOPI_PRIVATE_KEY") - WOPI_PUBLIC_KEY_CONTENT=$(openssl base64 -in "$WOPI_PUBLIC_KEY" -A) - WOPI_MODULUS=$(openssl rsa -pubin -inform "MS PUBLICKEYBLOB" -modulus -noout \ - -in "$WOPI_PUBLIC_KEY" | sed 's/Modulus=//' | \ - python3 -c "import sys,binascii,base64; print(base64.b64encode(binascii.unhexlify(sys.stdin.read().strip())).decode())") - - WOPI_EXPONENT=$(openssl rsa -pubin -inform "MS PUBLICKEYBLOB" -text -noout \ - -in "$WOPI_PUBLIC_KEY" | grep -oP '(?<=Exponent: )\d+') - - # Merge WOPI config into local.json - jq \ - --argjson wopiEnabled "true" \ - --arg wopiPrivateKey "$WOPI_PRIVATE_KEY_CONTENT" \ - --arg wopiPublicKey "$WOPI_PUBLIC_KEY_CONTENT" \ - --arg wopiModulus "$WOPI_MODULUS" \ - --arg wopiExponent "$WOPI_EXPONENT" \ - '.wopi.enable = $wopiEnabled | - .wopi.privateKey = $wopiPrivateKey | - .wopi.privateKeyOld = $wopiPrivateKey | - .wopi.publicKey = $wopiPublicKey | - .wopi.publicKeyOld = $wopiPublicKey | - .wopi.modulus = $wopiModulus | - .wopi.modulusOld = $wopiModulus | - .wopi.exponent = ($wopiExponent | tonumber) | - .wopi.exponentOld = ($wopiExponent | tonumber)' \ - "$CONFIG_FILE" > "${CONFIG_FILE}.tmp" - - mv "${CONFIG_FILE}.tmp" "$CONFIG_FILE" - echo "WOPI configuration injected successfully." -fi - -# Hand over to the official DocumentServer entrypoint -exec /entrypoint.sh "$@" diff --git a/config/euro-office/onlyoffice-docs-formats.json b/config/euro-office/onlyoffice-docs-formats.json deleted file mode 100644 index 75a0a9d..0000000 --- a/config/euro-office/onlyoffice-docs-formats.json +++ /dev/null @@ -1,604 +0,0 @@ -[ - { - "name": "doc", - "type": "word", - "actions": ["view", "auto-convert"], - "convert": ["docx", "bmp", "docm", "dotm", "dotx", "epub", "fb2", "gif", "html", "jpg", "md", "odt", "ott", "pdf", "pdfa", "png", "rtf", "txt"], - "mime": ["application/msword"] - }, - { - "name": "docm", - "type": "word", - "actions": ["view", "edit", "review", "comment", "encrypt"], - "convert": ["docx", "bmp", "dotm", "dotx", "epub", "fb2", "gif", "html", "jpg", "md", "odt", "ott", "pdf", "pdfa", "png", "rtf", "txt"], - "mime": ["application/vnd.ms-word.document.macroenabled.12"] - }, - { - "name": "docx", - "type": "word", - "actions": ["view", "edit", "review", "comment", "encrypt"], - "convert": ["bmp", "docm", "dotm", "dotx", "epub", "fb2", "gif", "html", "jpg", "md", "odt", "ott", "pdf", "pdfa", "png", "rtf", "txt"], - "mime": ["application/vnd.openxmlformats-officedocument.wordprocessingml.document"] - }, - { - "name": "dot", - "type": "word", - "actions": ["view", "auto-convert"], - "convert": ["docx", "bmp", "docm", "dotm", "dotx", "epub", "fb2", "gif", "html", "jpg", "md", "odt", "ott", "pdf", "pdfa", "png", "rtf", "txt"], - "mime": ["application/msword"] - }, - { - "name": "dotm", - "type": "word", - "actions": ["view", "edit", "review", "comment", "encrypt"], - "convert": ["docx", "bmp", "docm", "dotx", "epub", "fb2", "gif", "html", "jpg", "md", "odt", "ott", "pdf", "pdfa", "png", "rtf", "txt"], - "mime": ["application/vnd.ms-word.template.macroenabled.12"] - }, - { - "name": "dotx", - "type": "word", - "actions": ["view", "edit", "review", "comment", "encrypt"], - "convert": ["docx", "bmp", "docm", "dotm", "epub", "fb2", "gif", "html", "jpg", "md", "odt", "ott", "pdf", "pdfa", "png", "rtf", "txt"], - "mime": ["application/vnd.openxmlformats-officedocument.wordprocessingml.template"] - }, - { - "name": "epub", - "type": "word", - "actions": ["view", "lossy-edit", "auto-convert"], - "convert":["docx", "bmp", "docm", "dotm", "dotx", "fb2", "gif", "html", "jpg", "md", "odt", "ott", "pdf", "pdfa", "png", "rtf", "txt"], - "mime": ["application/epub+zip"] - }, - { - "name": "fb2", - "type": "word", - "actions": ["view", "lossy-edit", "auto-convert"], - "convert": ["docx", "bmp", "docm", "dotm", "dotx", "epub", "gif", "html", "jpg", "md", "odt", "ott", "pdf", "pdfa", "png", "rtf", "txt"], - "mime": ["text/fb2+xml", "application/x-fictionbook+xml"] - }, - { - "name": "fodt", - "type": "word", - "actions": ["view", "auto-convert"], - "convert": ["docx", "bmp", "docm", "dotm", "dotx", "epub", "fb2", "gif", "html", "jpg", "md", "odt", "ott", "pdf", "pdfa", "png", "rtf", "txt"], - "mime": ["application/vnd.oasis.opendocument.text-flat-xml"] - }, - { - "name": "gdoc", - "type": "word", - "actions": ["view"], - "convert": [], - "mime": ["application/vnd.google-apps.document"] - }, - { - "name": "hml", - "type": "word", - "actions": ["view", "auto-convert"], - "convert": ["docx", "bmp", "docm", "dotm", "dotx", "epub", "fb2", "gif", "html", "jpg", "md", "odt", "ott", "pdf", "pdfa", "png", "rtf", "txt"], - "mime": ["multipart/related"] - }, - { - "name": "htm", - "type": "word", - "actions": ["view", "auto-convert"], - "convert": ["docx", "bmp", "docm", "dotm", "dotx", "epub", "fb2", "gif", "jpg", "md", "odt", "ott", "pdf", "pdfa", "png", "rtf", "txt"], - "mime": ["text/html"] - }, - { - "name": "html", - "type": "word", - "actions": ["view", "lossy-edit", "auto-convert"], - "convert": ["docx", "bmp", "docm", "dotm", "dotx", "epub", "fb2", "gif", "jpg", "md", "odt", "ott", "pdf", "pdfa", "png", "rtf", "txt"], - "mime": ["text/html"] - }, - { - "name": "hwp", - "type": "word", - "actions": ["view", "auto-convert"], - "convert": ["docx", "bmp", "docm", "dotm", "dotx", "epub", "fb2", "gif", "html", "jpg", "md", "odt", "ott", "pdf", "pdfa", "png", "rtf", "txt"], - "mime": ["application/x-hwp", "application/x-hwp-v5"] - }, - { - "name": "hwpx", - "type": "word", - "actions": ["view", "auto-convert"], - "convert": ["docx", "bmp", "docm", "dotm", "dotx", "epub", "fb2", "gif", "html", "jpg", "md", "odt", "ott", "pdf", "pdfa", "png", "rtf", "txt"], - "mime": ["application/x-hwpx"] - }, - { - "name": "md", - "type": "word", - "actions": ["view", "auto-convert"], - "convert": ["docx", "bmp", "docm", "dotm", "dotx", "epub", "fb2", "gif", "html", "jpg", "odt", "ott", "pdf", "pdfa", "png", "rtf", "txt"], - "mime": ["text/markdown"] - }, - { - "name": "mht", - "type": "word", - "actions": ["view", "auto-convert"], - "convert": ["docx", "bmp", "docm", "dotm", "dotx", "epub", "fb2", "gif", "html", "jpg", "md", "odt", "ott", "pdf", "pdfa", "png", "rtf", "txt"], - "mime": ["message/rfc822"] - }, - { - "name": "mhtml", - "type": "word", - "actions": ["view", "auto-convert"], - "convert": ["docx", "bmp", "docm", "dotm", "dotx", "epub", "fb2", "gif", "html", "jpg", "md", "odt", "ott", "pdf", "pdfa", "png", "rtf", "txt"], - "mime": ["message/rfc822"] - }, - { - "name": "odt", - "type": "word", - "actions": ["view", "lossy-edit", "auto-convert", "review", "comment", "encrypt"], - "convert": ["docx", "bmp", "docm", "dotm", "dotx", "epub", "fb2", "gif", "html", "jpg", "md", "ott", "pdf", "pdfa", "png", "rtf", "txt"], - "mime": ["application/vnd.oasis.opendocument.text"] - }, - { - "name": "ott", - "type": "word", - "actions": ["view", "lossy-edit", "auto-convert", "review", "comment", "encrypt"], - "convert": ["docx", "bmp", "docm", "dotm", "dotx", "epub", "fb2", "gif", "html", "jpg", "md", "odt", "pdf", "pdfa", "png", "rtf", "txt"], - "mime": ["application/vnd.oasis.opendocument.text-template"] - }, - { - "name": "pages", - "type": "word", - "actions": ["view", "auto-convert"], - "convert": ["docx", "bmp", "docm", "dotm", "dotx", "epub", "fb2", "gif", "html", "jpg", "md", "odt", "ott", "pdf", "pdfa", "png", "rtf", "txt"], - "mime": ["application/vnd.apple.pages", "application/x-iwork-pages-sffpages"] - }, - { - "name": "rtf", - "type": "word", - "actions": ["view", "lossy-edit", "auto-convert", "review", "comment"], - "convert": ["docx", "bmp", "docm", "dotm", "dotx", "epub", "fb2", "gif", "html", "jpg", "md", "odt", "ott", "pdf", "pdfa", "png", "txt"], - "mime": ["application/rtf", "text/rtf"] - }, - { - "name": "stw", - "type": "word", - "actions": ["view", "auto-convert"], - "convert": ["docx", "bmp", "docm", "dotm", "dotx", "epub", "fb2", "gif", "html", "jpg", "md", "odt", "ott", "pdf", "pdfa", "png", "rtf", "txt"], - "mime": ["application/vnd.sun.xml.writer.template"] - }, - { - "name": "sxw", - "type": "word", - "actions": ["view", "auto-convert"], - "convert": ["docx", "bmp", "docm", "dotm", "dotx", "epub", "fb2", "gif", "html", "jpg", "md", "odt", "ott", "pdf", "pdfa", "png", "rtf", "txt"], - "mime": ["application/vnd.sun.xml.writer"] - }, - { - "name": "txt", - "type": "word", - "actions": ["view", "lossy-edit"], - "convert": ["docx", "bmp", "docm", "dotm", "dotx", "epub", "fb2", "gif", "html", "jpg", "md", "odt", "ott", "pdf", "pdfa", "png", "rtf"], - "mime": ["text/plain"] - }, - { - "name": "wps", - "type": "word", - "actions": ["view", "auto-convert"], - "convert": ["docx", "bmp", "docm", "dotm", "dotx", "epub", "fb2", "gif", "html", "jpg", "md", "odt", "ott", "pdf", "pdfa", "png", "rtf", "txt"], - "mime": ["application/vnd.ms-works"] - }, - { - "name": "wpt", - "type": "word", - "actions": ["view", "auto-convert"], - "convert": ["docx", "bmp", "docm", "dotm", "dotx", "epub", "fb2", "gif", "html", "jpg", "md", "odt", "ott", "pdf", "pdfa", "png", "rtf", "txt"], - "mime": [] - }, - { - "name": "xml", - "type": "word", - "actions": ["view", "auto-convert"], - "convert": ["docx", "xlsx", "bmp", "csv", "docm", "dotm", "dotx", "epub", "fb2", "gif", "html", "jpg", "md", "ods", "odt", "ots", "ott", "pdf", "pdfa", "png", "rtf", "txt", "tsv", "xlsm", "xltm", "xltx"], - "mime": ["application/xml", "text/xml"] - }, - { - "name": "csv", - "type": "cell", - "actions": ["view", "lossy-edit", "customfilter"], - "convert": ["xlsx", "bmp", "gif", "jpg", "ods", "ots", "pdf", "pdfa", "png", "tsv", "xlsm", "xltm", "xltx"], - "mime": ["text/csv", "application/csv", "text/x-comma-separated-values", "text/x-csv"] - }, - { - "name": "et", - "type": "cell", - "actions": ["view", "auto-convert"], - "convert": ["xlsx", "bmp", "csv", "gif", "jpg", "ods", "ots", "pdf", "pdfa", "png", "tsv", "xlsm", "xltm", "xltx"], - "mime": [] - }, - { - "name": "ett", - "type": "cell", - "actions": ["view", "auto-convert"], - "convert": ["xlsx", "bmp", "csv", "gif", "jpg", "ods", "ots", "pdf", "pdfa", "png", "tsv", "xlsm", "xltm", "xltx"], - "mime": [] - }, - { - "name": "fods", - "type": "cell", - "actions": ["view", "auto-convert"], - "convert": ["xlsx", "bmp", "csv", "gif", "jpg", "ods", "ots", "pdf", "pdfa", "png", "tsv", "xlsm", "xltm", "xltx"], - "mime": ["application/vnd.oasis.opendocument.spreadsheet-flat-xml"] - }, - { - "name": "gsheet", - "type": "cell", - "actions": ["view"], - "convert": [], - "mime": ["application/vnd.google-apps.spreadsheet"] - }, - { - "name": "numbers", - "type": "cell", - "actions": ["view", "auto-convert"], - "convert": ["xlsx", "bmp", "csv", "gif", "jpg", "ods", "ots", "pdf", "pdfa", "png", "tsv", "xlsm", "xltm", "xltx"], - "mime": ["application/vnd.apple.numbers", "application/x-iwork-numbers-sffnumbers"] - }, - { - "name": "ods", - "type": "cell", - "actions": ["view", "lossy-edit", "auto-convert", "customfilter", "comment", "encrypt"], - "convert": ["xlsx", "bmp", "csv", "gif", "jpg", "ots", "pdf", "pdfa", "png", "tsv", "xlsm", "xltm", "xltx"], - "mime": ["application/vnd.oasis.opendocument.spreadsheet"] - }, - { - "name": "ots", - "type": "cell", - "actions": ["view", "lossy-edit", "auto-convert", "customfilter", "comment", "encrypt"], - "convert": ["xlsx", "bmp", "csv", "gif", "jpg", "ods", "pdf", "pdfa", "png", "tsv", "tsv", "xlsm", "xltm", "xltx"], - "mime": ["application/vnd.oasis.opendocument.spreadsheet-template"] - }, - { - "name": "tsv", - "type": "cell", - "actions": ["view", "lossy-edit", "customfilter"], - "convert": ["xlsx", "bmp", "csv", "gif", "jpg", "ods", "ots", "pdf", "pdfa", "png", "xlsm", "xltm", "xltx"], - "mime": ["text/tab-separated-values"] - }, - { - "name": "sxc", - "type": "cell", - "actions": ["view", "auto-convert"], - "convert": ["xlsx", "bmp", "csv", "gif", "jpg", "ods", "ots", "pdf", "pdfa", "png", "tsv", "xlsm", "xltm", "xltx"], - "mime": ["application/vnd.sun.xml.calc"] - }, - { - "name": "xls", - "type": "cell", - "actions": ["view", "auto-convert"], - "convert": ["xlsx", "bmp", "csv", "gif", "jpg", "ods", "ots", "pdf", "pdfa", "png", "tsv", "xlsm", "xltm", "xltx"], - "mime": ["application/vnd.ms-excel"] - }, - { - "name": "xlsb", - "type": "cell", - "actions": ["view", "edit", "customfilter", "comment", "encrypt"], - "convert": ["xlsx", "bmp", "csv", "gif", "jpg", "ods", "ots", "pdf", "pdfa", "png", "tsv", "xlsm", "xltm", "xltx"], - "mime": ["application/vnd.ms-excel.sheet.binary.macroenabled.12"] - }, - { - "name": "xlsm", - "type": "cell", - "actions": ["view", "edit", "customfilter", "comment", "encrypt"], - "convert": ["xlsx", "bmp", "csv", "gif", "jpg", "ods", "ots", "pdf", "pdfa", "png", "tsv", "xltm", "xltx"], - "mime": ["application/vnd.ms-excel.sheet.macroenabled.12", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"] - }, - { - "name": "xlsx", - "type": "cell", - "actions": ["view", "edit", "customfilter", "comment", "encrypt"], - "convert": ["bmp", "csv", "gif", "jpg", "ods", "ots", "pdf", "pdfa", "png", "tsv", "xlsm", "xltm", "xltx"], - "mime": ["application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"] - }, - { - "name": "xlt", - "type": "cell", - "actions": ["view", "auto-convert"], - "convert": ["xlsx", "bmp", "csv", "gif", "jpg", "ods", "ots", "pdf", "pdfa", "png", "tsv", "xlsm", "xltm", "xltx"], - "mime": ["application/vnd.ms-excel"] - }, - { - "name": "xltm", - "type": "cell", - "actions": ["view", "edit", "customfilter", "comment", "encrypt"], - "convert": ["xlsx", "bmp", "csv", "gif", "jpg", "ods", "ots", "pdf", "pdfa", "png", "tsv", "xlsm", "xltx"], - "mime": ["application/vnd.ms-excel.template.macroenabled.12"] - }, - { - "name": "xltx", - "type": "cell", - "actions": ["view", "edit", "customfilter", "comment", "encrypt"], - "convert": ["xlsx", "bmp", "csv", "gif", "jpg", "ods", "ots", "pdf", "pdfa", "png", "tsv", "xlsm", "xltm"], - "mime": ["application/vnd.openxmlformats-officedocument.spreadsheetml.template"] - }, - { - "name": "dps", - "type": "slide", - "actions": ["view", "auto-convert"], - "convert": ["pptx", "bmp", "gif", "jpg", "odp", "otp", "pdf", "pdfa", "png", "potm", "potx", "ppsm", "ppsx", "pptm"], - "mime": [] - }, - { - "name": "dpt", - "type": "slide", - "actions": ["view", "auto-convert"], - "convert": ["pptx", "bmp", "gif", "jpg", "odp", "otp", "pdf", "pdfa", "png", "potm", "potx", "ppsm", "ppsx", "pptm"], - "mime": [] - }, - { - "name": "fodp", - "type": "slide", - "actions": ["view", "auto-convert"], - "convert": ["pptx", "bmp", "gif", "jpg", "odp", "otp", "pdf", "pdfa", "png", "potm", "potx", "ppsm", "ppsx", "pptm"], - "mime": ["application/vnd.oasis.opendocument.presentation-flat-xml"] - }, - { - "name": "gslides", - "type": "slide", - "actions": ["view"], - "convert": [], - "mime": ["application/vnd.google-apps.presentation"] - }, - { - "name": "key", - "type": "slide", - "actions": ["view", "auto-convert"], - "convert": ["pptx", "bmp", "gif", "jpg", "odp", "otp", "pdf", "pdfa", "png", "potm", "potx", "ppsm", "ppsx", "pptm", "txt"], - "mime": ["application/vnd.apple.keynote", "application/x-iwork-keynote-sffkey", "application/vnd.apple.keynote.13"] - }, - { - "name": "odg", - "type": "slide", - "actions": ["view", "auto-convert"], - "convert": ["pptx", "bmp", "gif", "jpg", "odp", "otp", "pdf", "pdfa", "png", "potm", "potx", "ppsm", "ppsx", "pptm", "txt"], - "mime": ["application/vnd.oasis.opendocument.graphics", "application/x-vnd.oasis.opendocument.graphics"] - }, - { - "name": "odp", - "type": "slide", - "actions": ["view", "lossy-edit", "auto-convert", "comment", "encrypt"], - "convert": ["pptx", "bmp", "gif", "jpg", "otp", "pdf", "pdfa", "png", "potm", "potx", "ppsm", "ppsx", "pptm", "txt"], - "mime": ["application/vnd.oasis.opendocument.presentation"] - }, - { - "name": "otp", - "type": "slide", - "actions": ["view", "lossy-edit", "auto-convert", "comment", "encrypt"], - "convert": ["pptx", "bmp", "gif", "jpg", "odp", "pdf", "pdfa", "png", "potm", "potx", "ppsm", "ppsx", "pptm", "txt"], - "mime": ["application/vnd.oasis.opendocument.presentation-template"] - }, - { - "name": "pot", - "type": "slide", - "actions": ["view", "auto-convert"], - "convert": ["pptx", "bmp", "gif", "jpg", "odp", "otp", "pdf", "pdfa", "png", "potm", "potx", "ppsm", "ppsx", "pptm", "txt"], - "mime": ["application/vnd.ms-powerpoint"] - }, - { - "name": "potm", - "type": "slide", - "actions": ["view", "edit", "comment", "encrypt"], - "convert": ["pptx", "bmp", "gif", "jpg", "odp", "otp", "pdf", "pdfa", "png", "potx", "ppsm", "ppsx", "pptm", "txt"], - "mime": ["application/vnd.ms-powerpoint.template.macroenabled.12"] - }, - { - "name": "potx", - "type": "slide", - "actions": ["view", "edit", "comment", "encrypt"], - "convert": ["pptx", "bmp", "gif", "jpg", "odp", "otp", "pdf", "pdfa", "png", "potm", "ppsm", "ppsx", "pptm", "txt"], - "mime": ["application/vnd.openxmlformats-officedocument.presentationml.template"] - }, - { - "name": "pps", - "type": "slide", - "actions": ["view", "auto-convert"], - "convert": ["pptx", "bmp", "gif", "jpg", "odp", "otp", "pdf", "pdfa", "png", "potm", "potx", "ppsm", "ppsx", "pptm", "txt"], - "mime": ["application/vnd.ms-powerpoint"] - }, - { - "name": "ppsm", - "type": "slide", - "actions": ["view", "edit", "comment", "encrypt"], - "convert": ["pptx", "bmp", "gif", "jpg", "odp", "otp", "pdf", "pdfa", "png", "potm", "potx", "ppsx", "pptm", "txt"], - "mime": ["application/vnd.ms-powerpoint.slideshow.macroenabled.12"] - }, - { - "name": "ppsx", - "type": "slide", - "actions": ["view", "edit", "comment", "encrypt"], - "convert": ["pptx", "bmp", "gif", "jpg", "odp", "otp", "pdf", "pdfa", "png", "potm", "potx", "ppsm", "pptm", "txt"], - "mime": ["application/vnd.openxmlformats-officedocument.presentationml.slideshow"] - }, - { - "name": "ppt", - "type": "slide", - "actions": ["view", "auto-convert"], - "convert": ["pptx", "bmp", "gif", "jpg", "odp", "otp", "pdf", "pdfa", "png", "potm", "potx", "ppsm", "ppsx", "pptm", "txt"], - "mime": ["application/vnd.ms-powerpoint"] - }, - { - "name": "pptm", - "type": "slide", - "actions": ["view", "edit", "comment", "encrypt"], - "convert": ["pptx", "bmp", "gif", "jpg", "odp", "otp", "pdf", "pdfa", "png", "potm", "potx", "ppsm", "ppsx", "txt"], - "mime": ["application/vnd.ms-powerpoint.presentation.macroenabled.12"] - }, - { - "name": "pptx", - "type": "slide", - "actions": ["view", "edit", "comment", "encrypt"], - "convert": ["bmp", "gif", "jpg", "odp", "otp", "pdf", "pdfa", "png", "potm", "potx", "ppsm", "ppsx", "pptm", "txt"], - "mime": ["application/vnd.openxmlformats-officedocument.presentationml.presentation"] - }, - { - "name": "sxi", - "type": "slide", - "actions": ["view", "auto-convert"], - "convert": ["pptx", "bmp", "gif", "jpg", "odp", "otp", "pdf", "pdfa", "png", "potm", "potx", "ppsm", "ppsx", "pptm", "txt"], - "mime": ["application/vnd.sun.xml.impress"] - }, - { - "name": "djvu", - "type": "pdf", - "actions": ["view"], - "convert": ["bmp", "gif", "jpg", "pdf", "pdfa", "png"], - "mime": ["image/vnd.djvu"] - }, - { - "name": "docxf", - "type": "pdf", - "actions": ["view"], - "convert": ["docx", "bmp", "docm", "dotm", "dotx", "epub", "fb2", "gif", "html", "jpg", "md", "odt", "ott", "pdf", "pdfa", "png", "rtf", "txt"], - "mime": ["application/vnd.openxmlformats-officedocument.wordprocessingml.document.docxf"] - }, - { - "name": "oform", - "type": "pdf", - "actions": ["view"], - "convert": ["pdf"], - "mime": ["application/vnd.openxmlformats-officedocument.wordprocessingml.document.oform"] - }, - { - "name": "oxps", - "type": "pdf", - "actions": ["view"], - "convert": ["docx", "bmp", "docm", "dotm", "dotx", "epub", "fb2", "gif", "html", "jpg", "md", "odt", "ott", "pdf", "pdfa", "png", "rtf", "txt"], - "mime": ["application/oxps"] - }, - { - "name": "pdf", - "type": "pdf", - "actions": ["view", "edit", "comment", "fill", "encrypt"], - "convert": ["docx", "bmp", "docm", "dotm", "dotx", "epub", "fb2", "gif", "html", "jpg", "md", "odt", "ott", "pdfa", "png", "rtf", "txt"], - "mime": ["application/pdf", "application/acrobat", "application/nappdf", "application/x-pdf", "image/pdf"] - }, - { - "name": "xps", - "type": "pdf", - "actions": ["view"], - "convert": ["docx", "bmp", "docm", "dotm", "dotx", "epub", "fb2", "gif", "html", "jpg", "md", "odt", "ott", "pdf", "pdfa", "png", "rtf", "txt"], - "mime": ["application/vnd.ms-xpsdocument", "application/xps"] - }, - { - "name": "vsdx", - "type": "diagram", - "actions": ["view"], - "convert": ["bmp", "gif", "jpg", "pdf", "pdfa", "png"], - "mime": ["application/vnd.ms-visio.drawing, application/vnd.visio2013", "application/vnd.visio"] - }, - { - "name": "vsdm", - "type": "diagram", - "actions": ["view"], - "convert": ["bmp", "gif", "jpg", "pdf", "pdfa", "png"], - "mime": ["application/vnd.ms-visio.drawing.macroEnabled.12"] - }, - { - "name": "vssm", - "type": "diagram", - "actions": ["view"], - "convert": ["bmp", "gif", "jpg", "pdf", "pdfa", "png"], - "mime": ["application/vnd.ms-visio.stencil.macroEnabled.12"] - }, - { - "name": "vssx", - "type": "diagram", - "actions": ["view"], - "convert": ["bmp", "gif", "jpg", "pdf", "pdfa", "png"], - "mime": ["application/vnd.ms-visio.stencil"] - }, - { - "name": "vstm", - "type": "diagram", - "actions": ["view"], - "convert": ["bmp", "gif", "jpg", "pdf", "pdfa", "png"], - "mime": ["application/vnd.ms-visio.template.macroEnabled.12"] - }, - { - "name": "vstx", - "type": "diagram", - "actions": ["view"], - "convert": ["bmp", "gif", "jpg", "pdf", "pdfa", "png"], - "mime": ["application/vnd.ms-visio.template"] - }, - { - "name": "bmp", - "type": "", - "actions": [], - "convert": [], - "mime": ["image/bmp"] - }, - { - "name": "gif", - "type": "", - "actions": [], - "convert": [], - "mime": ["image/gif"] - }, - { - "name": "heic", - "type": "", - "actions": [], - "convert": [], - "mime": ["image/heic"] - }, - { - "name": "heif", - "type": "", - "actions": [], - "convert": [], - "mime": ["image/heif"] - }, - { - "name": "jpg", - "type": "", - "actions": [], - "convert": [], - "mime": ["image/jpeg"] - }, - { - "name": "pdfa", - "type": "", - "actions": [], - "convert": [], - "mime": ["application/pdf", "application/acrobat", "application/nappdf", "application/x-pdf", "image/pdf"] - }, - { - "name": "png", - "type": "", - "actions": [], - "convert": [], - "mime": ["image/png"] - }, - { - "name": "tif", - "type": "", - "actions": [], - "convert": [], - "mime": ["image/tif", "image/x-tif", "application/tif", "application/x-tif"] - }, - { - "name": "tiff", - "type": "", - "actions": [], - "convert": [], - "mime": ["image/tiff", "image/x-tiff", "application/tiff", "application/x-tiff"] - }, - { - "name": "webp", - "type": "", - "actions": [], - "convert": [], - "mime": ["image/webp"] - }, - { - "name": "zip", - "type": "", - "actions": [], - "convert": [], - "mime": ["application/zip"] - } -] diff --git a/weboffice/euroffice.yml b/weboffice/euroffice.yml index 661000e..e2f930a 100644 --- a/weboffice/euroffice.yml +++ b/weboffice/euroffice.yml @@ -55,18 +55,12 @@ services: opencloud-net: environment: WOPI_ENABLED: "true" - JWT_SECRET: "${EURO_OFFICE_JWT_SECRET:-changeme}" # self-signed certificates USE_UNAUTHORIZED_STORAGE: "${INSECURE:-false}" - entrypoint: - - /bin/sh - - /init-wopi.sh volumes: # Mount local TrueType fonts so the container can use system fonts # (e.g. Microsoft fonts like Arial, Calibri, Cambria by installing the `ttf-mscorefonts-installer` package). - /usr/share/fonts/truetype:/usr/share/fonts/truetype/more:ro - - ./config/euro-office/init-wopi.sh:/init-wopi.sh:ro - - ./config/euro-office/onlyoffice-docs-formats.json:/var/www/onlyoffice/documentserver/document-formats/onlyoffice-docs-formats.json logging: driver: ${LOG_DRIVER:-local} restart: always From 0636b2c8715529472cc9d0fdf9806d9672a27810 Mon Sep 17 00:00:00 2001 From: "v.scharf" Date: Tue, 16 Jun 2026 14:52:23 +0200 Subject: [PATCH 10/14] set OC_EVENTS_ENDPOINT for collaboration (EO) --- weboffice/euroffice.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/weboffice/euroffice.yml b/weboffice/euroffice.yml index e2f930a..681153e 100644 --- a/weboffice/euroffice.yml +++ b/weboffice/euroffice.yml @@ -41,6 +41,7 @@ services: COLLABORATION_APP_PROOF_DISABLE: "true" COLLABORATION_LOG_LEVEL: ${LOG_LEVEL:-info} OC_URL: https://${OC_DOMAIN:-cloud.opencloud.test}${TRAEFIK_PORT_HTTPS:+:}${TRAEFIK_PORT_HTTPS:-} + OC_EVENTS_ENDPOINT: "opencloud:9233" volumes: # configure the .env file to use own paths instead of docker internal volumes - ${OC_CONFIG_DIR:-opencloud-config}:/etc/opencloud From 4d3e787e2df28cfea03c1e962c178265c939357f Mon Sep 17 00:00:00 2001 From: Michael Barz Date: Fri, 19 Jun 2026 09:36:25 +0200 Subject: [PATCH 11/14] fix: collabora healthcheck without curl --- weboffice/collabora.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/weboffice/collabora.yml b/weboffice/collabora.yml index 576dcaa..71cf32c 100644 --- a/weboffice/collabora.yml +++ b/weboffice/collabora.yml @@ -83,7 +83,13 @@ services: entrypoint: [ '/bin/bash', '-c' ] command: [ 'coolconfig generate-proof-key && /start-collabora-online.sh' ] healthcheck: - test: [ "CMD", "curl", "-f", "http://localhost:9980/hosting/discovery" ] + test: + [ + "CMD", + "bash", + "-c", + "exec 3<>/dev/tcp/127.0.0.1/9980 && printf 'GET /hosting/discovery HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n' >&3 && cat <&3 | head -1 | grep -q '200 OK'" + ] interval: 15s timeout: 10s retries: 5 From 73b02b77d89c2e90f02db76f49b162e2870088b7 Mon Sep 17 00:00:00 2001 From: Connor Date: Fri, 2 Jan 2026 20:31:26 -0500 Subject: [PATCH 12/14] feat: make role assignment settings configurable Allow PROXY_ROLE_ASSIGNMENT_DRIVER and GRAPH_ASSIGN_DEFAULT_USER_ROLE to be set via environment variables in .env file. - PROXY_ROLE_ASSIGNMENT_DRIVER defaults to oidc - GRAPH_ASSIGN_DEFAULT_USER_ROLE defaults to false When using PROXY_ROLE_ASSIGNMENT_DRIVER=default, set GRAPH_ASSIGN_DEFAULT_USER_ROLE=true to assign the 'user' role to new users. --- .env.example | 8 ++++++++ idm/external-idp.yml | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/.env.example b/.env.example index 9e721aa..81401e3 100644 --- a/.env.example +++ b/.env.example @@ -323,6 +323,14 @@ LDAP_BIND_PASSWORD= ## Autoprovisioning Mode ## # Use together with idm/external-idp.yml +# Role assignment driver for the proxy. Defaults to "oidc". +# Possible values: "oidc", "default" +# When set to "oidc", roles are assigned based on OIDC claims. +# When set to "default", all users get the 'user' role assigned. +PROXY_ROLE_ASSIGNMENT_DRIVER= +# Assign the default 'user' role to new users. Defaults to "false". +# Set to "true" when using PROXY_ROLE_ASSIGNMENT_DRIVER=default +GRAPH_ASSIGN_DEFAULT_USER_ROLE= # If you want to use a keycloak for local testing, you can use testing/external-keycloak.yml and testing/ldap-manager.yml # Domain of your Identity Provider. IDP_DOMAIN= diff --git a/idm/external-idp.yml b/idm/external-idp.yml index fb66889..cf7b775 100644 --- a/idm/external-idp.yml +++ b/idm/external-idp.yml @@ -25,7 +25,7 @@ services: WEBFINGER_IOS_OIDC_CLIENT_SCOPES: ${WEBFINGER_IOS_OIDC_CLIENT_SCOPES} WEBFINGER_DESKTOP_OIDC_CLIENT_ID: ${WEBFINGER_DESKTOP_OIDC_CLIENT_ID} WEBFINGER_DESKTOP_OIDC_CLIENT_SCOPES: ${WEBFINGER_DESKTOP_OIDC_CLIENT_SCOPES} - PROXY_ROLE_ASSIGNMENT_DRIVER: "oidc" + PROXY_ROLE_ASSIGNMENT_DRIVER: ${PROXY_ROLE_ASSIGNMENT_DRIVER:-oidc} OC_OIDC_ISSUER: ${IDP_ISSUER_URL:-https://keycloak.opencloud.test/realms/openCloud} # This specifies to start all services except idm and idp. These are replaced by external services. OC_EXCLUDE_RUN_SERVICES: idm,idp @@ -47,7 +47,7 @@ services: OC_LDAP_DISABLE_USER_MECHANISM: "attribute" OC_ADMIN_USER_ID: "" SETTINGS_SETUP_DEFAULT_ASSIGNMENTS: "false" - GRAPH_ASSIGN_DEFAULT_USER_ROLE: "false" + GRAPH_ASSIGN_DEFAULT_USER_ROLE: ${GRAPH_ASSIGN_DEFAULT_USER_ROLE:-false} GRAPH_USERNAME_MATCH: "none" # We need to set the IDP_DOMAIN to allow the CSP rules to be set correctly IDP_DOMAIN: ${IDP_DOMAIN:-keycloak.opencloud.test} From 5268ad506b8dbd935d30f109d40753efc2575407 Mon Sep 17 00:00:00 2001 From: Michael Barz Date: Fri, 19 Jun 2026 20:26:16 +0200 Subject: [PATCH 13/14] feat: move collaboration into the opencloud process --- .env.example | 6 ++-- README.md | 26 +++++++++++------ external-proxy/collabora.yml | 4 --- external-proxy/euroffice-exposed.yml | 4 --- external-proxy/euroffice.yml | 4 --- traefik/collabora.yml | 10 ------- traefik/euroffice.yml | 10 ------- weboffice/collabora.yml | 43 ++++++---------------------- weboffice/euroffice.yml | 42 ++++++--------------------- 9 files changed, 37 insertions(+), 112 deletions(-) diff --git a/.env.example b/.env.example index 81401e3..0588b8e 100644 --- a/.env.example +++ b/.env.example @@ -219,9 +219,9 @@ TIKA_IMAGE= # Domain of Collabora, where you can find the frontend. # Defaults to "collabora.opencloud.test" COLLABORA_DOMAIN= -# Domain of the wopiserver which handles Collabora. -# Defaults to "wopiserver.opencloud.test" -WOPISERVER_DOMAIN= +# NOTE: The WOPI server runs inside the main OpenCloud process and is served by +# the OpenCloud proxy on the main OpenCloud domain (OC_DOMAIN) under the /wopi and +# /collaboration paths. It no longer needs its own domain. # Admin user for Collabora. # Defaults to "admin". # Collabora Admin Panel URL: diff --git a/README.md b/README.md index 5c7fa14..c9816d7 100644 --- a/README.md +++ b/README.md @@ -109,11 +109,11 @@ This setup includes: ### With Collabora Online > [!NOTE] -> Collabora Online and [Euro Office](#with-euro-office) are mutually exclusive web office backends — both use the same `collaboration` (WOPI) service. Enable only one of them at a time. +> Collabora Online and [Euro Office](#with-euro-office) are mutually exclusive web office backends — both use the same `collaboration` (WOPI) service, which runs inside the main OpenCloud process. Enable only one of them at a time. Include Collabora for document editing using either method: -> **DNS Requirements**: This setup requires DNS entries for the main OpenCloud domain, Collabora subdomain, and WOPI server subdomain. Configure DNS A/AAAA records for your domains (e.g., `cloud.example.com`, `collabora.example.com`, `wopiserver.example.com`) or use a wildcard DNS entry (`*.example.com`). +> **DNS Requirements**: This setup requires DNS entries for the main OpenCloud domain and the Collabora subdomain. The WOPI server is served by OpenCloud on the main domain, so it does not need its own subdomain. Configure DNS A/AAAA records for your domains (e.g., `cloud.example.com`, `collabora.example.com`) or use a wildcard DNS entry (`*.example.com`). Using `-f` flags: ```bash @@ -128,17 +128,22 @@ COMPOSE_FILE=docker-compose.yml:weboffice/collabora.yml:traefik/opencloud.yml:tr > **For local development only**: Add to `/etc/hosts`: > ``` > 127.0.0.1 collabora.opencloud.test -> 127.0.0.1 wopiserver.opencloud.test > ``` +> [!IMPORTANT] +> **Upgrading from a previous setup**: The `collaboration` (WOPI) service no longer runs as a separate container or on its own `wopiserver.*` domain — it now runs inside the main OpenCloud process and is served by the OpenCloud proxy on the main domain under the `/wopi` and `/collaboration` paths. When upgrading: +> - Pull the latest compose files and recreate the stack (`docker compose up -d`). The old `collaboration` container is removed automatically. +> - You can retire the `wopiserver.*` DNS entry (and its `/etc/hosts` line), its reverse-proxy/Traefik route, and the `WOPISERVER_DOMAIN` variable in `.env` — all are now unused. +> - If you run behind an external proxy, make sure it forwards `/wopi` and `/collaboration` on the OpenCloud domain to OpenCloud (port 9200). Forwarding the whole OpenCloud domain, as already configured, covers this. + ### With Euro Office > [!NOTE] -> Euro Office and [Collabora Online](#with-collabora-online) are mutually exclusive web office backends — both use the same `collaboration` (WOPI) service. Enable only one of them at a time. +> Euro Office and [Collabora Online](#with-collabora-online) are mutually exclusive web office backends — both use the same `collaboration` (WOPI) service, which runs inside the main OpenCloud process. Enable only one of them at a time. Include Euro Office for document editing using either method: -> **DNS Requirements**: This setup requires DNS entries for the main OpenCloud domain, Euro Office subdomain, and WOPI server subdomain. Configure DNS A/AAAA records for your domains (e.g., `cloud.example.com`, `euro-office.example.com`, `wopiserver.example.com`) or use a wildcard DNS entry (`*.example.com`). +> **DNS Requirements**: This setup requires DNS entries for the main OpenCloud domain and the Euro Office subdomain. The WOPI server is served by OpenCloud on the main domain, so it does not need its own subdomain. Configure DNS A/AAAA records for your domains (e.g., `cloud.example.com`, `euro-office.example.com`) or use a wildcard DNS entry (`*.example.com`). Using `-f` flags: ```bash @@ -153,12 +158,14 @@ COMPOSE_FILE=docker-compose.yml:weboffice/euroffice.yml:traefik/opencloud.yml:tr > **For local development only**: Add to `/etc/hosts`: > ``` > 127.0.0.1 euro-office.opencloud.test -> 127.0.0.1 wopiserver.opencloud.test > ``` > [!IMPORTANT] > Set a strong `EURO_OFFICE_JWT_SECRET` in your `.env` file for production. The default value (`changeme`) is intended for local development only. +> [!NOTE] +> Upgrading from a previous setup? See [Upgrading from a previous setup](#with-collabora-online) under Collabora Online — the WOPI server changes (no more separate container or `wopiserver.*` domain) apply to Euro Office as well. + ### With Full Text Search Enable full text search capabilities with Apache Tika using either method: @@ -258,7 +265,8 @@ COMPOSE_FILE=docker-compose.yml:weboffice/collabora.yml:external-proxy/opencloud This exposes the necessary ports: - OpenCloud: 9200 - Collabora: 9980 -- WOPI server: 9300 + +The WOPI server runs inside the OpenCloud process and is served on the OpenCloud port (9200) under the `/wopi` and `/collaboration` paths, so no separate port needs to be exposed for it. To use Euro Office instead of Collabora behind an external proxy, swap the web office compose files: @@ -274,7 +282,8 @@ COMPOSE_FILE=docker-compose.yml:weboffice/euroffice.yml:external-proxy/opencloud This exposes the necessary ports: - OpenCloud: 9200 - Euro Office: 9900 -- WOPI server: 9300 + +As with Collabora, the WOPI server is served on the OpenCloud port (9200) under the `/wopi` and `/collaboration` paths and needs no separate port. > [!WARNING] > `external-proxy/euroffice.yml` binds the exposed ports to `127.0.0.1` only. If your external proxy runs on a different host, use `external-proxy/euroffice-exposed.yml`, which binds to all interfaces (`0.0.0.0`). Only expose these ports when you know what you are doing. @@ -392,7 +401,6 @@ Key variables: | `OC_DATA_DIR` | Data directory path | (Docker volume) | | `INSECURE` | Skip certificate validation | true | | `COLLABORA_DOMAIN` | Collabora domain | collabora.opencloud.test | -| `WOPISERVER_DOMAIN` | WOPI server domain | wopiserver.opencloud.test | | `EURO_OFFICE_DOMAIN` | Euro Office document server domain | euro-office.opencloud.test | | `EURO_OFFICE_JWT_SECRET` | JWT secret for Euro Office (change for production!) | changeme | | `EURO_OFFICE_DOCKER_IMAGE` | Euro Office Docker image | ghcr.io/euro-office/documentserver | diff --git a/external-proxy/collabora.yml b/external-proxy/collabora.yml index 6458c5e..f708e9f 100644 --- a/external-proxy/collabora.yml +++ b/external-proxy/collabora.yml @@ -1,9 +1,5 @@ --- services: - collaboration: - ports: - # expose the wopi server on localhost - - "127.0.0.1:9300:9300" collabora: ports: # expose the collabora server on localhost diff --git a/external-proxy/euroffice-exposed.yml b/external-proxy/euroffice-exposed.yml index 69d56c6..21f1d9b 100644 --- a/external-proxy/euroffice-exposed.yml +++ b/external-proxy/euroffice-exposed.yml @@ -1,10 +1,6 @@ --- # only expose the ports when you know what you are doing! services: - collaboration: - ports: - # expose the wopi server on all interfaces - - "0.0.0.0:9300:9300" euro-office: ports: # expose the euro-office document server on all interfaces diff --git a/external-proxy/euroffice.yml b/external-proxy/euroffice.yml index 6b64222..f04849f 100644 --- a/external-proxy/euroffice.yml +++ b/external-proxy/euroffice.yml @@ -1,9 +1,5 @@ --- services: - collaboration: - ports: - # expose the wopi server on localhost - - "127.0.0.1:9300:9300" euro-office: ports: # expose the euro-office document server on localhost diff --git a/traefik/collabora.yml b/traefik/collabora.yml index 808b9e3..1fb4cee 100644 --- a/traefik/collabora.yml +++ b/traefik/collabora.yml @@ -5,16 +5,6 @@ services: opencloud-net: aliases: - ${COLLABORA_DOMAIN:-collabora.opencloud.test} - - ${WOPISERVER_DOMAIN:-wopiserver.opencloud.test} - collaboration: - labels: - - "traefik.enable=true" - - "traefik.http.routers.collaboration.entrypoints=https" - - "traefik.http.routers.collaboration.rule=Host(`${WOPISERVER_DOMAIN:-wopiserver.opencloud.test}`)" - - "traefik.http.routers.collaboration.${TRAEFIK_SERVICES_TLS_CONFIG}" - - "traefik.http.routers.collaboration.service=collaboration" - - "traefik.http.routers.collaboration.middlewares=hsts-header" - - "traefik.http.services.collaboration.loadbalancer.server.port=9300" collabora: labels: - "traefik.enable=true" diff --git a/traefik/euroffice.yml b/traefik/euroffice.yml index 60435f8..49d221c 100644 --- a/traefik/euroffice.yml +++ b/traefik/euroffice.yml @@ -5,16 +5,6 @@ services: opencloud-net: aliases: - ${EURO_OFFICE_DOMAIN:-euro-office.opencloud.test} - - ${WOPISERVER_DOMAIN:-wopiserver.opencloud.test} - collaboration: - labels: - - "traefik.enable=true" - - "traefik.http.routers.collaboration.entrypoints=https" - - "traefik.http.routers.collaboration.rule=Host(`${WOPISERVER_DOMAIN:-wopiserver.opencloud.test}`)" - - "traefik.http.routers.collaboration.${TRAEFIK_SERVICES_TLS_CONFIG}" - - "traefik.http.routers.collaboration.service=collaboration" - - "traefik.http.routers.collaboration.middlewares=hsts-header" - - "traefik.http.services.collaboration.loadbalancer.server.port=9300" euro-office: labels: - "traefik.enable=true" diff --git a/weboffice/collabora.yml b/weboffice/collabora.yml index 71cf32c..6ec3ba7 100644 --- a/weboffice/collabora.yml +++ b/weboffice/collabora.yml @@ -6,48 +6,22 @@ services: # this is needed for setting the correct CSP header COLLABORA_DOMAIN: ${COLLABORA_DOMAIN:-collabora.opencloud.test} TRAEFIK_PORT_HTTPS: ${TRAEFIK_PORT_HTTPS:+:}${TRAEFIK_PORT_HTTPS:-} - # expose nats and the reva gateway for the collaboration service - NATS_NATS_HOST: 0.0.0.0 - GATEWAY_GRPC_ADDR: 0.0.0.0:9142 + # run the collaboration (WOPI) service inside the main opencloud process, + # appended to any user defined services in START_ADDITIONAL_SERVICES + OC_ADD_RUN_SERVICES: ${START_ADDITIONAL_SERVICES:-}${START_ADDITIONAL_SERVICES:+,}collaboration # make collabora the secure view app FRONTEND_APP_HANDLER_SECURE_VIEW_APP_ADDR: eu.opencloud.api.collaboration GRAPH_AVAILABLE_ROLES: "b1e2218d-eef8-4d4c-b82d-0f1a1b48f3b5,a8d5fe5e-96e3-418d-825b-534dbdf22b99,fb6c3e19-e378-47e5-b277-9732f9de6e21,58c63c02-1d89-4572-916a-870abc5a1b7d,2d00ce52-1fc2-4dbc-8b95-a73b73395f5a,1c996275-f1c9-4e71-abdf-a42f6495e960,312c0871-5ef7-4b3a-85b6-0e4074c64049,aa97fe03-7980-45ac-9e50-b325749fd7e6" - - collaboration: - # renovate: depName=opencloudeu/opencloud-rolling - image: ${OC_DOCKER_IMAGE:-opencloudeu/opencloud-rolling}:${OC_DOCKER_TAG:-6.2.0} - user: ${OC_CONTAINER_UID_GID:-1000:1000} - networks: - opencloud-net: - depends_on: - opencloud: - condition: service_started - collabora: - condition: service_healthy - entrypoint: - - /bin/sh - command: [ "-c", "opencloud collaboration server" ] - environment: - COLLABORATION_GRPC_ADDR: 0.0.0.0:9301 - COLLABORATION_HTTP_ADDR: 0.0.0.0:9300 - MICRO_REGISTRY: "nats-js-kv" - MICRO_REGISTRY_ADDRESS: "opencloud:9233" - COLLABORATION_WOPI_SRC: https://${WOPISERVER_DOMAIN:-wopiserver.opencloud.test}${TRAEFIK_PORT_HTTPS:+:}${TRAEFIK_PORT_HTTPS:-} + # collaboration service configuration; the WOPI endpoint is served by the + # opencloud proxy on the opencloud domain (/wopi and /collaboration routes), + # so no separate wopiserver domain, route or port is needed + COLLABORATION_WOPI_SRC: https://${OC_DOMAIN:-cloud.opencloud.test}${TRAEFIK_PORT_HTTPS:+:}${TRAEFIK_PORT_HTTPS:-} COLLABORATION_APP_NAME: "CollaboraOnline" COLLABORATION_APP_PRODUCT: "Collabora" COLLABORATION_APP_ADDR: https://${COLLABORA_DOMAIN:-collabora.opencloud.test}${TRAEFIK_PORT_HTTPS:+:}${TRAEFIK_PORT_HTTPS:-} COLLABORATION_APP_ICON: https://${COLLABORA_DOMAIN:-collabora.opencloud.test}${TRAEFIK_PORT_HTTPS:+:}${TRAEFIK_PORT_HTTPS:-}/favicon.ico COLLABORATION_APP_INSECURE: "${INSECURE:-true}" COLLABORATION_CS3API_DATAGATEWAY_INSECURE: "${INSECURE:-true}" - COLLABORATION_LOG_LEVEL: ${LOG_LEVEL:-info} - OC_URL: https://${OC_DOMAIN:-cloud.opencloud.test}${TRAEFIK_PORT_HTTPS:+:}${TRAEFIK_PORT_HTTPS:-} - OC_EVENTS_ENDPOINT: "opencloud:9233" - volumes: - # configure the .env file to use own paths instead of docker internal volumes - - ${OC_CONFIG_DIR:-opencloud-config}:/etc/opencloud - logging: - driver: ${LOG_DRIVER:-local} - restart: always collabora: image: collabora/code:26.04.1.4.1 @@ -55,7 +29,8 @@ services: networks: opencloud-net: environment: - aliasgroup1: https://${WOPISERVER_DOMAIN:-wopiserver.opencloud.test}${TRAEFIK_PORT_HTTPS:+:}${TRAEFIK_PORT_HTTPS:-} + # WOPI host allowlist; the WOPI endpoint is served by the opencloud proxy on the opencloud domain + aliasgroup1: https://${OC_DOMAIN:-cloud.opencloud.test}${TRAEFIK_PORT_HTTPS:+:}${TRAEFIK_PORT_HTTPS:-} DONT_GEN_SSL_CERT: "YES" extra_params: | --o:ssl.enable=${COLLABORA_SSL_ENABLE:-true} \ diff --git a/weboffice/euroffice.yml b/weboffice/euroffice.yml index 681153e..239cd13 100644 --- a/weboffice/euroffice.yml +++ b/weboffice/euroffice.yml @@ -6,32 +6,13 @@ services: # this is needed for setting the correct CSP header EURO_OFFICE_DOMAIN: ${EURO_OFFICE_DOMAIN:-euro-office.opencloud.test} TRAEFIK_PORT_HTTPS: ${TRAEFIK_PORT_HTTPS:+:}${TRAEFIK_PORT_HTTPS:-} - # expose nats and the reva gateway for the collaboration service - NATS_NATS_HOST: 0.0.0.0 - GATEWAY_GRPC_ADDR: 0.0.0.0:9142 - volumes: - - ./config/euro-office/app-registry.yaml:/etc/opencloud/app-registry.yaml - - collaboration: - # renovate: depName=opencloudeu/opencloud-rolling - image: ${OC_DOCKER_IMAGE:-opencloudeu/opencloud-rolling}:${OC_DOCKER_TAG:-6.2.0} - user: ${OC_CONTAINER_UID_GID:-1000:1000} - networks: - opencloud-net: - depends_on: - opencloud: - condition: service_started - euro-office: - condition: service_healthy - entrypoint: - - /bin/sh - command: [ "-c", "opencloud collaboration server" ] - environment: - COLLABORATION_GRPC_ADDR: 0.0.0.0:9301 - COLLABORATION_HTTP_ADDR: 0.0.0.0:9300 - MICRO_REGISTRY: "nats-js-kv" - MICRO_REGISTRY_ADDRESS: "opencloud:9233" - COLLABORATION_WOPI_SRC: https://${WOPISERVER_DOMAIN:-wopiserver.opencloud.test}${TRAEFIK_PORT_HTTPS:+:}${TRAEFIK_PORT_HTTPS:-} + # run the collaboration (WOPI) service inside the main opencloud process, + # appended to any user defined services in START_ADDITIONAL_SERVICES + OC_ADD_RUN_SERVICES: ${START_ADDITIONAL_SERVICES:-}${START_ADDITIONAL_SERVICES:+,}collaboration + # collaboration service configuration; the WOPI endpoint is served by the + # opencloud proxy on the opencloud domain (/wopi and /collaboration routes), + # so no separate wopiserver domain, route or port is needed + COLLABORATION_WOPI_SRC: https://${OC_DOMAIN:-cloud.opencloud.test}${TRAEFIK_PORT_HTTPS:+:}${TRAEFIK_PORT_HTTPS:-} COLLABORATION_APP_NAME: "Euro-Office" COLLABORATION_APP_PRODUCT: "OnlyOffice" COLLABORATION_APP_ADDR: https://${EURO_OFFICE_DOMAIN:-euro-office.opencloud.test}${TRAEFIK_PORT_HTTPS:+:}${TRAEFIK_PORT_HTTPS:-} @@ -39,15 +20,8 @@ services: COLLABORATION_APP_INSECURE: "${INSECURE:-true}" COLLABORATION_CS3API_DATAGATEWAY_INSECURE: "${INSECURE:-true}" COLLABORATION_APP_PROOF_DISABLE: "true" - COLLABORATION_LOG_LEVEL: ${LOG_LEVEL:-info} - OC_URL: https://${OC_DOMAIN:-cloud.opencloud.test}${TRAEFIK_PORT_HTTPS:+:}${TRAEFIK_PORT_HTTPS:-} - OC_EVENTS_ENDPOINT: "opencloud:9233" volumes: - # configure the .env file to use own paths instead of docker internal volumes - - ${OC_CONFIG_DIR:-opencloud-config}:/etc/opencloud - logging: - driver: ${LOG_DRIVER:-local} - restart: always + - ./config/euro-office/app-registry.yaml:/etc/opencloud/app-registry.yaml euro-office: image: ${EURO_OFFICE_DOCKER_IMAGE:-ghcr.io/euro-office/documentserver}:${EURO_OFFICE_DOCKER_TAG:-latest} From 9cee17c253e0b7596a8d261c509a5fccd48df38c Mon Sep 17 00:00:00 2001 From: Michael Barz Date: Mon, 22 Jun 2026 15:08:13 +0200 Subject: [PATCH 14/14] fix: remove collaboration from external proxy --- external-proxy/collabora-exposed.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/external-proxy/collabora-exposed.yml b/external-proxy/collabora-exposed.yml index a6bb388..c25f265 100644 --- a/external-proxy/collabora-exposed.yml +++ b/external-proxy/collabora-exposed.yml @@ -1,10 +1,6 @@ --- # only expose the ports when you know what you are doing! services: - collaboration: - ports: - # expose the wopi server on all interfaces - - "0.0.0.0:9300:9300" collabora: ports: # expose the collabora server on all interfaces