From 46b0e1120adc8c90d731ed0b57d7bb730ba4aa04 Mon Sep 17 00:00:00 2001 From: alexz Date: Mon, 6 Apr 2026 19:06:02 +0000 Subject: [PATCH] Add ONLYOFFICE Docs app Online office suite with document, spreadsheet, and presentation editing. Includes external PostgreSQL, Redis, and RabbitMQ services with auto-generated secrets for JWT, database, and message queue credentials. Co-Authored-By: Claude Opus 4.6 (1M context) --- apps/onlyoffice-docs/config.json | 87 ++++++++++++ apps/onlyoffice-docs/docker-compose.json | 132 +++++++++++++++++++ apps/onlyoffice-docs/metadata/description.md | 56 ++++++++ apps/onlyoffice-docs/metadata/logo.jpg | Bin 0 -> 21910 bytes 4 files changed, 275 insertions(+) create mode 100644 apps/onlyoffice-docs/config.json create mode 100644 apps/onlyoffice-docs/docker-compose.json create mode 100644 apps/onlyoffice-docs/metadata/description.md create mode 100644 apps/onlyoffice-docs/metadata/logo.jpg diff --git a/apps/onlyoffice-docs/config.json b/apps/onlyoffice-docs/config.json new file mode 100644 index 0000000..4795e05 --- /dev/null +++ b/apps/onlyoffice-docs/config.json @@ -0,0 +1,87 @@ +{ + "$schema": "../app-info-schema.json", + "name": "ONLYOFFICE Docs", + "id": "onlyoffice-docs", + "available": true, + "short_desc": "Online office suite for document editing and collaboration", + "author": "Ascensio System SIA", + "port": 8044, + "categories": ["utilities", "documents"], + "description": "ONLYOFFICE Docs is an online office suite comprising viewers and editors for texts, spreadsheets and presentations, fully compatible with Office Open XML formats (.docx, .xlsx, .pptx) and enabling collaborative editing in real time.", + "tipi_version": 7, + "dynamic_config": true, + "version": "8.2", + "source": "https://github.com/ONLYOFFICE/DocumentServer", + "website": "https://www.onlyoffice.com/", + "exposable": true, + "url_suffix": "/", + "supported_architectures": ["amd64"], + "no_gui": false, + "deprecated": false, + "min_tipi_version": "4.5.0", + "created_at": 1712361600000, + "updated_at": 1712361600000, + "form_fields": [ + { + "type": "random", + "label": "JWT Secret", + "env_variable": "ONLYOFFICE_JWT_SECRET", + "min": 32, + "encoding": "hex" + }, + { + "type": "random", + "label": "Database Password", + "env_variable": "ONLYOFFICE_DB_PASSWORD", + "min": 24, + "encoding": "hex" + }, + { + "type": "random", + "label": "RabbitMQ Password", + "env_variable": "ONLYOFFICE_RABBITMQ_PASSWORD", + "min": 24, + "encoding": "hex" + }, + { + "type": "boolean", + "label": "Enable JWT", + "hint": "Enable JSON Web Token validation for secure API access", + "required": false, + "default": true, + "env_variable": "ONLYOFFICE_JWT_ENABLED" + }, + { + "type": "text", + "label": "JWT Header", + "hint": "HTTP header name for JWT token (default: Authorization)", + "required": false, + "default": "Authorization", + "env_variable": "ONLYOFFICE_JWT_HEADER" + }, + { + "type": "boolean", + "label": "JWT in Body", + "hint": "Enable token validation in request body", + "required": false, + "default": false, + "env_variable": "ONLYOFFICE_JWT_IN_BODY" + }, + { + "type": "boolean", + "label": "Allow Unauthorized Storage", + "hint": "Set to true if using self-signed certificates for your storage server (e.g., Nextcloud)", + "required": false, + "default": false, + "env_variable": "ONLYOFFICE_USE_UNAUTHORIZED_STORAGE" + }, + { + "type": "boolean", + "label": "Enable WOPI", + "hint": "Enable WOPI protocol handlers for integration with WOPI-compatible apps", + "required": false, + "default": false, + "env_variable": "ONLYOFFICE_WOPI_ENABLED" + } + ] +} diff --git a/apps/onlyoffice-docs/docker-compose.json b/apps/onlyoffice-docs/docker-compose.json new file mode 100644 index 0000000..ffc6136 --- /dev/null +++ b/apps/onlyoffice-docs/docker-compose.json @@ -0,0 +1,132 @@ +{ + "schemaVersion": 2, + "$schema": "https://schemas.runtipi.io/dynamic-compose.json", + "services": [ + { + "name": "onlyoffice-docs", + "image": "onlyoffice/documentserver:8.2", + "isMain": true, + "internalPort": 80, + "dependsOn": { + "onlyoffice-docs-db": { + "condition": "service_healthy" + }, + "onlyoffice-docs-redis": { + "condition": "service_healthy" + }, + "onlyoffice-docs-rabbitmq": { + "condition": "service_healthy" + } + }, + "environment": { + "JWT_ENABLED": "${ONLYOFFICE_JWT_ENABLED:-true}", + "JWT_SECRET": "${ONLYOFFICE_JWT_SECRET}", + "JWT_HEADER": "${ONLYOFFICE_JWT_HEADER:-Authorization}", + "JWT_IN_BODY": "${ONLYOFFICE_JWT_IN_BODY:-false}", + "USE_UNAUTHORIZED_STORAGE": "${ONLYOFFICE_USE_UNAUTHORIZED_STORAGE:-false}", + "WOPI_ENABLED": "${ONLYOFFICE_WOPI_ENABLED:-false}", + "NGINX_WORKER_PROCESSES": "auto", + "NGINX_WORKER_CONNECTIONS": "4096", + "GENERATE_FONTS": "true", + "DB_TYPE": "postgres", + "DB_HOST": "onlyoffice-docs-db", + "DB_PORT": "5432", + "DB_NAME": "onlyoffice", + "DB_USER": "onlyoffice", + "DB_PWD": "${ONLYOFFICE_DB_PASSWORD}", + "REDIS_SERVER_HOST": "onlyoffice-docs-redis", + "REDIS_SERVER_PORT": "6379", + "AMQP_URI": "amqp://${ONLYOFFICE_RABBITMQ_USER:-onlyoffice}:${ONLYOFFICE_RABBITMQ_PASSWORD}@onlyoffice-docs-rabbitmq:5672/", + "AMQP_TYPE": "rabbitmq" + }, + "volumes": [ + { + "hostPath": "${APP_DATA_DIR}/data/logs", + "containerPath": "/var/log/onlyoffice" + }, + { + "hostPath": "${APP_DATA_DIR}/data/data", + "containerPath": "/var/www/onlyoffice/Data" + }, + { + "hostPath": "${APP_DATA_DIR}/data/lib", + "containerPath": "/var/lib/onlyoffice" + }, + { + "hostPath": "${APP_DATA_DIR}/data/fonts", + "containerPath": "/usr/share/fonts/truetype/custom" + } + ], + "healthCheck": { + "command": "curl -f http://localhost/healthcheck", + "interval": "30s", + "timeout": "10s", + "retries": 3, + "startPeriod": "60s" + } + }, + { + "name": "onlyoffice-docs-db", + "image": "postgres:15-alpine", + "isMain": false, + "environment": { + "POSTGRES_DB": "onlyoffice", + "POSTGRES_USER": "onlyoffice", + "POSTGRES_PASSWORD": "${ONLYOFFICE_DB_PASSWORD}" + }, + "volumes": [ + { + "hostPath": "${APP_DATA_DIR}/data/postgresql", + "containerPath": "/var/lib/postgresql/data" + } + ], + "healthCheck": { + "command": "pg_isready -U onlyoffice -d onlyoffice", + "interval": "10s", + "timeout": "5s", + "retries": 5, + "startPeriod": "10s" + } + }, + { + "name": "onlyoffice-docs-redis", + "image": "redis:7-alpine", + "isMain": false, + "volumes": [ + { + "hostPath": "${APP_DATA_DIR}/data/redis", + "containerPath": "/data" + } + ], + "healthCheck": { + "command": "redis-cli ping", + "interval": "10s", + "timeout": "5s", + "retries": 5, + "startPeriod": "10s" + } + }, + { + "name": "onlyoffice-docs-rabbitmq", + "image": "rabbitmq:3-alpine", + "isMain": false, + "environment": { + "RABBITMQ_DEFAULT_USER": "${ONLYOFFICE_RABBITMQ_USER:-onlyoffice}", + "RABBITMQ_DEFAULT_PASS": "${ONLYOFFICE_RABBITMQ_PASSWORD}" + }, + "volumes": [ + { + "hostPath": "${APP_DATA_DIR}/data/rabbitmq", + "containerPath": "/var/lib/rabbitmq" + } + ], + "healthCheck": { + "command": "rabbitmq-diagnostics -q ping", + "interval": "10s", + "timeout": "5s", + "retries": 5, + "startPeriod": "30s" + } + } + ] +} diff --git a/apps/onlyoffice-docs/metadata/description.md b/apps/onlyoffice-docs/metadata/description.md new file mode 100644 index 0000000..919cf71 --- /dev/null +++ b/apps/onlyoffice-docs/metadata/description.md @@ -0,0 +1,56 @@ +# ONLYOFFICE Docs + +ONLYOFFICE Docs is a powerful online office suite for viewing and editing documents, spreadsheets, and presentations directly in your browser. + +## Features + +### Document Editing +- **Document Editor** - Create and edit text documents with full formatting support +- **Spreadsheet Editor** - Work with complex spreadsheets, formulas, and charts +- **Presentation Editor** - Build professional presentations with slides and animations + +### Collaboration +- **Real-time co-editing** - Multiple users can edit the same document simultaneously +- **Track changes** - Review and accept/reject modifications +- **Comments** - Add and reply to comments in documents + +### Format Support +Full compatibility with Microsoft Office formats: +- Documents: DOC, DOCX, ODT, TXT, RTF, HTML, EPUB +- Spreadsheets: XLS, XLSX, ODS, CSV +- Presentations: PPT, PPTX, ODP + +### Integration +ONLYOFFICE Docs can be integrated with: +- Nextcloud +- ownCloud +- Seafile +- Confluence +- Alfresco +- SharePoint +- Many other platforms via API + +## Configuration + +### JWT Secret (Required) +The JWT secret is used to secure communication between your application and ONLYOFFICE Docs. Generate a strong random string for production use. + +### Self-Signed Certificates +If your storage server (e.g., Nextcloud) uses self-signed SSL certificates, enable the "Allow Unauthorized Storage" option. + +### WOPI Support +Enable WOPI if you're integrating with WOPI-compatible applications like Collabora Online or Microsoft Office Online Server. + +## System Requirements + +- **CPU**: Dual core 2 GHz or better +- **RAM**: 4 GB minimum (8 GB recommended) +- **Storage**: 40 GB minimum free space +- **Architecture**: amd64 only + +## Links + +- [Official Documentation](https://helpcenter.onlyoffice.com/docs/) +- [GitHub Repository](https://github.com/ONLYOFFICE/DocumentServer) +- [API Documentation](https://api.onlyoffice.com/) +- [Integration Examples](https://helpcenter.onlyoffice.com/docs/installation) diff --git a/apps/onlyoffice-docs/metadata/logo.jpg b/apps/onlyoffice-docs/metadata/logo.jpg new file mode 100644 index 0000000000000000000000000000000000000000..53b289c9d0fe1c20a2ca938025a02991d4411da7 GIT binary patch literal 21910 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 literal 0 HcmV?d00001