From f08fa4d427f660c08f6ede39022a67dd680b9cba Mon Sep 17 00:00:00 2001 From: okxlin <61420215+okxlin@users.noreply.github.com> Date: Tue, 28 Jul 2026 11:23:14 +0800 Subject: [PATCH] Add ONLYOFFICE Kasm workspace --- .../1.19.0-rolling-weekly/.env.sample | 5 ++ .../1.19.0-rolling-weekly/data.yml | 69 ++++++++++++++++++ .../1.19.0-rolling-weekly/docker-compose.yml | 35 +++++++++ .../1.19.0-rolling-weekly/scripts/init.sh | 50 +++++++++++++ .../scripts/uninstall.sh | 4 + .../1.19.0-rolling-weekly/scripts/upgrade.sh | 4 + apps/only-office-kasm/README.md | 55 ++++++++++++++ apps/only-office-kasm/data.yml | 29 ++++++++ apps/only-office-kasm/logo-LICENSE.txt | 10 +++ apps/only-office-kasm/logo.png | Bin 0 -> 10351 bytes 10 files changed, 261 insertions(+) create mode 100644 apps/only-office-kasm/1.19.0-rolling-weekly/.env.sample create mode 100644 apps/only-office-kasm/1.19.0-rolling-weekly/data.yml create mode 100644 apps/only-office-kasm/1.19.0-rolling-weekly/docker-compose.yml create mode 100755 apps/only-office-kasm/1.19.0-rolling-weekly/scripts/init.sh create mode 100755 apps/only-office-kasm/1.19.0-rolling-weekly/scripts/uninstall.sh create mode 100755 apps/only-office-kasm/1.19.0-rolling-weekly/scripts/upgrade.sh create mode 100644 apps/only-office-kasm/README.md create mode 100644 apps/only-office-kasm/data.yml create mode 100644 apps/only-office-kasm/logo-LICENSE.txt create mode 100644 apps/only-office-kasm/logo.png diff --git a/apps/only-office-kasm/1.19.0-rolling-weekly/.env.sample b/apps/only-office-kasm/1.19.0-rolling-weekly/.env.sample new file mode 100644 index 000000000..9e5bb150d --- /dev/null +++ b/apps/only-office-kasm/1.19.0-rolling-weekly/.env.sample @@ -0,0 +1,5 @@ +PANEL_APP_PORT_HTTPS=41013 +HTTP_PWD=replace-with-a-random-value +SHM_SIZE=1024m +APP_DATA_DIR=./data +CONTAINER_NAME= diff --git a/apps/only-office-kasm/1.19.0-rolling-weekly/data.yml b/apps/only-office-kasm/1.19.0-rolling-weekly/data.yml new file mode 100644 index 000000000..570575933 --- /dev/null +++ b/apps/only-office-kasm/1.19.0-rolling-weekly/data.yml @@ -0,0 +1,69 @@ +additionalProperties: + formFields: + - default: 41013 + edit: true + envKey: PANEL_APP_PORT_HTTPS + labelEn: HTTPS Port + labelZh: HTTPS 端口 + label: + en: HTTPS Port + zh: HTTPS 端口 + zh-Hant: HTTPS 連接埠 + ja: HTTPS ポート + ko: HTTPS 포트 + ru: Порт HTTPS + ms: Port HTTPS + pt-br: Porta HTTPS + required: true + rule: paramPort + type: number + - default: "" + edit: true + envKey: HTTP_PWD + labelEn: Access Password + labelZh: 访问密码 + label: + en: Access Password + zh: 访问密码 + zh-Hant: 存取密碼 + ja: アクセスパスワード + ko: 접속 비밀번호 + ru: Пароль доступа + ms: Kata Laluan Akses + pt-br: Senha de Acesso + random: true + required: true + rule: paramComplexity + type: password + - default: 1024m + edit: true + envKey: SHM_SIZE + labelEn: Shared Memory Size + labelZh: 共享内存大小 + label: + en: Shared Memory Size + zh: 共享内存大小 + zh-Hant: 共享記憶體大小 + ja: 共有メモリサイズ + ko: 공유 메모리 크기 + ru: Размер общей памяти + ms: Saiz Memori Dikongsi + pt-br: Tamanho da Memória Compartilhada + required: true + type: text + - default: ./data + edit: true + envKey: APP_DATA_DIR + labelEn: Data Directory + labelZh: 数据目录 + label: + en: Data Directory + zh: 数据目录 + zh-Hant: 資料目錄 + ja: データディレクトリ + ko: 데이터 디렉터리 + ru: Каталог данных + ms: Direktori Data + pt-br: Diretório de Dados + required: true + type: text diff --git a/apps/only-office-kasm/1.19.0-rolling-weekly/docker-compose.yml b/apps/only-office-kasm/1.19.0-rolling-weekly/docker-compose.yml new file mode 100644 index 000000000..a05ba8427 --- /dev/null +++ b/apps/only-office-kasm/1.19.0-rolling-weekly/docker-compose.yml @@ -0,0 +1,35 @@ +services: + only-office-kasm: + image: "kasmweb/only-office:1.19.0-rolling-weekly@sha256:c2d9651d9d600d1633dbc2d56fbfa1a67dbbe780d498d6de0677594780e68d50" + container_name: ${CONTAINER_NAME} + restart: unless-stopped + networks: + - 1panel-network + ports: + - "${PANEL_APP_PORT_HTTPS}:6901" + environment: + - VNC_PW=${HTTP_PWD} + shm_size: ${SHM_SIZE} + cap_drop: + - ALL + security_opt: + - no-new-privileges:true + healthcheck: + test: + - CMD-SHELL + - >- + curl --insecure --fail --silent --show-error + --user "kasm_user:$$VNC_PW" + https://127.0.0.1:6901/ + interval: 30s + timeout: 10s + start_period: 90s + retries: 5 + volumes: + - "${APP_DATA_DIR}:/home/kasm-user" + labels: + createdBy: "Apps" + +networks: + 1panel-network: + external: true diff --git a/apps/only-office-kasm/1.19.0-rolling-weekly/scripts/init.sh b/apps/only-office-kasm/1.19.0-rolling-weekly/scripts/init.sh new file mode 100755 index 000000000..338044ef8 --- /dev/null +++ b/apps/only-office-kasm/1.19.0-rolling-weekly/scripts/init.sh @@ -0,0 +1,50 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)" +ENV_FILE="${ENV_FILE:-$ROOT_DIR/.env}" + +read_env_value() { + local key="$1" + [[ -f "$ENV_FILE" ]] || return 0 + local value + value="$(sed -n "s/^${key}=//p" "$ENV_FILE" | tail -n 1)" + case "$value" in + \"*\") value="${value#\"}"; value="${value%\"}" ;; + \'*\') value="${value#\'}"; value="${value%\'}" ;; + esac + printf '%s\n' "$value" +} + +data_raw="${APP_DATA_DIR:-}" +if [[ -z "$data_raw" ]]; then + data_raw="$(read_env_value APP_DATA_DIR)" +fi +data_raw="${data_raw:-./data}" + +[[ "$data_raw" != /* ]] || { + printf '%s\n' 'APP_DATA_DIR must be a relative path' >&2 + exit 1 +} + +data_dir="$(realpath -m -- "$ROOT_DIR/${data_raw#./}")" +case "$data_dir" in + "$ROOT_DIR"/*) ;; + *) + printf '%s\n' 'APP_DATA_DIR must remain inside the application version directory' >&2 + exit 1 + ;; +esac + +mkdir -p -- "$data_dir" +resolved_data_dir="$(realpath -e -- "$data_dir")" +case "$resolved_data_dir" in + "$ROOT_DIR"/*) ;; + *) + printf '%s\n' 'APP_DATA_DIR resolves outside the application version directory' >&2 + exit 1 + ;; +esac + +chown 1000:1000 -- "$resolved_data_dir" +chmod 0700 -- "$resolved_data_dir" diff --git a/apps/only-office-kasm/1.19.0-rolling-weekly/scripts/uninstall.sh b/apps/only-office-kasm/1.19.0-rolling-weekly/scripts/uninstall.sh new file mode 100755 index 000000000..e043feffb --- /dev/null +++ b/apps/only-office-kasm/1.19.0-rolling-weekly/scripts/uninstall.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Preserve APP_DATA_DIR so uninstall does not destroy user files. diff --git a/apps/only-office-kasm/1.19.0-rolling-weekly/scripts/upgrade.sh b/apps/only-office-kasm/1.19.0-rolling-weekly/scripts/upgrade.sh new file mode 100755 index 000000000..692e341e2 --- /dev/null +++ b/apps/only-office-kasm/1.19.0-rolling-weekly/scripts/upgrade.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail + +"$(dirname "$0")/init.sh" diff --git a/apps/only-office-kasm/README.md b/apps/only-office-kasm/README.md new file mode 100644 index 000000000..1baee7588 --- /dev/null +++ b/apps/only-office-kasm/README.md @@ -0,0 +1,55 @@ +# Only Office (Kasm) + +## 产品介绍 + +Only Office (Kasm) 将 Only Office 作为浏览器工作区运行。镜像由 Kasm Technologies 构建,1Panel 应用包直接使用固定 digest,不在本地重打包镜像。 + +## 主要功能 + +- 在浏览器中使用完整的 Linux 图形界面 +- 将用户配置、下载和工作文件保存在独立数据目录 +- 通过 KasmVNC 的 HTTPS 入口和安装时随机生成的密码访问 + +## 访问说明 + +安装后访问 `https://<服务器 IP>:`,用户名为 `kasm_user`,密码为安装表单中的访问密码。镜像使用自签名证书,浏览器首次访问会显示证书警告;公网部署应在可信反向代理后使用有效 HTTPS 证书,并限制来源地址。 + +Kasm 官方说明,音频、上传、下载和麦克风透传等部分功能只有在完整 Kasm Workspaces 平台编排下才能完整使用。独立部署不应假定这些集成功能可用。 + +## 数据持久化 + +`APP_DATA_DIR` 挂载到 `/home/kasm-user`,保存用户配置和文件,默认值为版本目录下的 `./data`。该值必须是版本目录内的相对路径;生命周期脚本会拒绝绝对路径、目录逃逸和指向目录外的符号链接。卸载或迁移前请备份该目录;不要把多个实例指向同一目录。 + +`SHM_SIZE` 控制浏览器工作区共享内存,默认 `1024m`。大型文件或高分辨率会话可适当提高,但必须确认主机有足够内存。 + +## 版本与安全说明 + +- `workspaces-images` 使用 MIT 许可文本(SPDX: MIT),但上游声明只覆盖该仓库直接维护的源码,不自动覆盖镜像内第三方应用或依赖。各产品许可和商标条款仍独立适用;本应用包只引用上游镜像,不重分发镜像内容。 +- 本包固定 Kasm 官方 `1.19.0-rolling-weekly` 在 2026-07-22 发布的 amd64 digest `sha256:c2d9651d9d600d1633dbc2d56fbfa1a67dbbe780d498d6de0677594780e68d50`,不会随远端标签静默变化。 +- 2026-07-28 对此精确 digest 的 fresh Trivy 扫描结果为 `0 Critical / 0 High`。 +- 容器以上游 UID 1000 运行,移除全部 Linux capabilities,并启用 `no-new-privileges`。上游启动过程需要写入 `/dockerstartup` 和 `/var/run/pulse`,因此不能使用只读根文件系统。 +- `VNC_PW` 通过 1Panel 随机密码字段传入并保存在应用 `.env` 中。不要复用其他系统密码,并限制 1Panel、Docker 和应用目录的读取权限。 + +## Introduction + +Only Office (Kasm) runs Only Office as a browser-accessible workspace. Kasm Technologies builds the image, and this package references a pinned digest without rebuilding it. + +The `workspaces-images` source uses the MIT license text (SPDX: MIT) only for code directly maintained in that repository. It does not extend to third-party applications or dependencies in the image. This package references the upstream image without redistributing its contents. + +## Features + +- Full Linux graphical application streamed through the browser +- Per-install persistence for user settings, downloads, and working files +- KasmVNC HTTPS access protected by an installation-time random password + +Open `https://:`, sign in as `kasm_user`, and use the access password generated during installation. The image presents a self-signed certificate. Use a trusted HTTPS reverse proxy and restrict source addresses for Internet-facing deployments. + +`APP_DATA_DIR` persists `/home/kasm-user`. The image is pinned to the 2026-07-22 `1.19.0-rolling-weekly` digest. A fresh Trivy scan of this exact digest on 2026-07-28 found `0 Critical / 0 High`. + +## References + +- Product website: +- Kasm official registry: +- Docker Hub image and stand-alone instructions: +- Pinned image source: +- Source license: diff --git a/apps/only-office-kasm/data.yml b/apps/only-office-kasm/data.yml new file mode 100644 index 000000000..1fdf09da2 --- /dev/null +++ b/apps/only-office-kasm/data.yml @@ -0,0 +1,29 @@ +name: Only Office (Kasm) +tags: + - 实用工具 +title: 浏览器版 Only Office +description: 可通过浏览器访问的 Only Office 工作区 +additionalProperties: + key: only-office-kasm + name: Only Office (Kasm) + tags: + - Tool + shortDescZh: 可通过浏览器访问的 Only Office 工作区 + shortDescEn: Browser-accessible Only Office workspace + description: + en: Browser-accessible Only Office workspace + zh: 可通过浏览器访问的 Only Office 工作区 + zh-Hant: 可透過瀏覽器存取的 Only Office 工作區 + ja: ブラウザーから利用できる Only Office ワークスペース + ko: 브라우저에서 사용할 수 있는 Only Office 워크스페이스 + ru: Рабочее пространство Only Office с доступом через браузер + ms: Ruang kerja Only Office yang boleh diakses melalui pelayar + pt-br: Ambiente Only Office acessível pelo navegador + type: tool + crossVersionUpdate: true + limit: 0 + website: https://www.onlyoffice.com/ + github: https://github.com/kasmtech/workspaces-images/blob/bafab6d531eefd5a5aa6f2c9088ebc8f02e12fae/dockerfile-kasm-only-office + document: https://hub.docker.com/r/kasmweb/only-office + architectures: + - amd64 diff --git a/apps/only-office-kasm/logo-LICENSE.txt b/apps/only-office-kasm/logo-LICENSE.txt new file mode 100644 index 000000000..17e9ba10b --- /dev/null +++ b/apps/only-office-kasm/logo-LICENSE.txt @@ -0,0 +1,10 @@ +Only Office (Kasm) typographic workspace icon + +Created in this repository on 2026-07-28 with ImageMagick using only geometric shapes and the text "Only Office" and "WEB WORKSPACE". +Font: DejaVu Sans and DejaVu Sans Bold +Font source: https://dejavu-fonts.github.io/ +Font license: Bitstream Vera font license; DejaVu changes are public domain +Font license text: https://dejavu-fonts.github.io/License.html +SHA-256: 3552f2f29df1f036ac08285c9a5037f2166a1ac060b8db8f10763a76b1305ff3 + +The generated composition is original project artwork. Product names may be trademarks of their respective owners and are used only for identification. diff --git a/apps/only-office-kasm/logo.png b/apps/only-office-kasm/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..f1920256a5d5a35f552944b04c5643800195c5ff GIT binary patch literal 10351 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

Zw0F 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 literal 0 HcmV?d00001