From 87cbdc05e3c0f77c9925586f695ed0e367e1a709 Mon Sep 17 00:00:00 2001 From: zerox80 Date: Fri, 10 Apr 2026 09:46:52 +0200 Subject: [PATCH 1/4] 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 4f594547..c1a44990 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 00000000..65c0107f --- /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 00000000..a95ad6ac --- /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 00000000..75a0a9d9 --- /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 cde4b1ef..cf6f528c 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 00000000..ff500344 --- /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 00000000..6b344c40 --- /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 00000000..ea4795c8 --- /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 00000000..e8da97a4 --- /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 2/4] 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 e8da97a4..14ffe1f6 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 3/4] 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 c1a44990..5c687dcb 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 a95ad6ac..00000000 --- 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 ff500344..69d56c68 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 6b344c40..6b64222a 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 ea4795c8..60435f89 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 14ffe1f6..200918dd 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 4/4] 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 00000000..8893c357 --- /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 200918dd..803ed77b 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}