From 0aa09816c900247aa06edfbdda1c2aacf4e64c53 Mon Sep 17 00:00:00 2001 From: okxlin <61420215+okxlin@users.noreply.github.com> Date: Tue, 28 Jul 2026 11:23:13 +0800 Subject: [PATCH] Add FileZilla 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/filezilla-kasm/README.md | 55 ++++++++++++++ apps/filezilla-kasm/data.yml | 30 ++++++++ apps/filezilla-kasm/logo-LICENSE.txt | 10 +++ apps/filezilla-kasm/logo.png | Bin 0 -> 9260 bytes 10 files changed, 262 insertions(+) create mode 100644 apps/filezilla-kasm/1.19.0-rolling-weekly/.env.sample create mode 100644 apps/filezilla-kasm/1.19.0-rolling-weekly/data.yml create mode 100644 apps/filezilla-kasm/1.19.0-rolling-weekly/docker-compose.yml create mode 100755 apps/filezilla-kasm/1.19.0-rolling-weekly/scripts/init.sh create mode 100755 apps/filezilla-kasm/1.19.0-rolling-weekly/scripts/uninstall.sh create mode 100755 apps/filezilla-kasm/1.19.0-rolling-weekly/scripts/upgrade.sh create mode 100644 apps/filezilla-kasm/README.md create mode 100644 apps/filezilla-kasm/data.yml create mode 100644 apps/filezilla-kasm/logo-LICENSE.txt create mode 100644 apps/filezilla-kasm/logo.png diff --git a/apps/filezilla-kasm/1.19.0-rolling-weekly/.env.sample b/apps/filezilla-kasm/1.19.0-rolling-weekly/.env.sample new file mode 100644 index 000000000..09664e294 --- /dev/null +++ b/apps/filezilla-kasm/1.19.0-rolling-weekly/.env.sample @@ -0,0 +1,5 @@ +PANEL_APP_PORT_HTTPS=41006 +HTTP_PWD=replace-with-a-random-value +SHM_SIZE=1024m +APP_DATA_DIR=./data +CONTAINER_NAME= diff --git a/apps/filezilla-kasm/1.19.0-rolling-weekly/data.yml b/apps/filezilla-kasm/1.19.0-rolling-weekly/data.yml new file mode 100644 index 000000000..020cf4264 --- /dev/null +++ b/apps/filezilla-kasm/1.19.0-rolling-weekly/data.yml @@ -0,0 +1,69 @@ +additionalProperties: + formFields: + - default: 41006 + 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/filezilla-kasm/1.19.0-rolling-weekly/docker-compose.yml b/apps/filezilla-kasm/1.19.0-rolling-weekly/docker-compose.yml new file mode 100644 index 000000000..2197bd571 --- /dev/null +++ b/apps/filezilla-kasm/1.19.0-rolling-weekly/docker-compose.yml @@ -0,0 +1,35 @@ +services: + filezilla-kasm: + image: "kasmweb/filezilla:1.19.0-rolling-weekly@sha256:27a55f492c6b717f1bcf9c47708b542d0bbdc2cfec0530a8c3e692bd9fe3e2ea" + 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/filezilla-kasm/1.19.0-rolling-weekly/scripts/init.sh b/apps/filezilla-kasm/1.19.0-rolling-weekly/scripts/init.sh new file mode 100755 index 000000000..338044ef8 --- /dev/null +++ b/apps/filezilla-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/filezilla-kasm/1.19.0-rolling-weekly/scripts/uninstall.sh b/apps/filezilla-kasm/1.19.0-rolling-weekly/scripts/uninstall.sh new file mode 100755 index 000000000..e043feffb --- /dev/null +++ b/apps/filezilla-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/filezilla-kasm/1.19.0-rolling-weekly/scripts/upgrade.sh b/apps/filezilla-kasm/1.19.0-rolling-weekly/scripts/upgrade.sh new file mode 100755 index 000000000..692e341e2 --- /dev/null +++ b/apps/filezilla-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/filezilla-kasm/README.md b/apps/filezilla-kasm/README.md new file mode 100644 index 000000000..28109b753 --- /dev/null +++ b/apps/filezilla-kasm/README.md @@ -0,0 +1,55 @@ +# FileZilla (Kasm) + +## 产品介绍 + +FileZilla (Kasm) 将 FileZilla 作为浏览器工作区运行。镜像由 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,arm64 digest `sha256:27a55f492c6b717f1bcf9c47708b542d0bbdc2cfec0530a8c3e692bd9fe3e2ea`,不会随远端标签静默变化。 +- 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 + +FileZilla (Kasm) runs FileZilla 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/filezilla-kasm/data.yml b/apps/filezilla-kasm/data.yml new file mode 100644 index 000000000..280c3286c --- /dev/null +++ b/apps/filezilla-kasm/data.yml @@ -0,0 +1,30 @@ +name: FileZilla (Kasm) +tags: + - 实用工具 +title: 浏览器版 FileZilla +description: 可通过浏览器访问的 FileZilla 工作区 +additionalProperties: + key: filezilla-kasm + name: FileZilla (Kasm) + tags: + - Tool + shortDescZh: 可通过浏览器访问的 FileZilla 工作区 + shortDescEn: Browser-accessible FileZilla workspace + description: + en: Browser-accessible FileZilla workspace + zh: 可通过浏览器访问的 FileZilla 工作区 + zh-Hant: 可透過瀏覽器存取的 FileZilla 工作區 + ja: ブラウザーから利用できる FileZilla ワークスペース + ko: 브라우저에서 사용할 수 있는 FileZilla 워크스페이스 + ru: Рабочее пространство FileZilla с доступом через браузер + ms: Ruang kerja FileZilla yang boleh diakses melalui pelayar + pt-br: Ambiente FileZilla acessível pelo navegador + type: tool + crossVersionUpdate: true + limit: 0 + website: https://filezilla-project.org/ + github: https://github.com/kasmtech/workspaces-images/blob/bafab6d531eefd5a5aa6f2c9088ebc8f02e12fae/dockerfile-kasm-filezilla + document: https://hub.docker.com/r/kasmweb/filezilla + architectures: + - amd64 + - arm64 diff --git a/apps/filezilla-kasm/logo-LICENSE.txt b/apps/filezilla-kasm/logo-LICENSE.txt new file mode 100644 index 000000000..1d8a0ff54 --- /dev/null +++ b/apps/filezilla-kasm/logo-LICENSE.txt @@ -0,0 +1,10 @@ +FileZilla (Kasm) typographic workspace icon + +Created in this repository on 2026-07-28 with ImageMagick using only geometric shapes and the text "FileZilla" 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: 501d2d3eaa279ed9019760170983d2caeba0d65dbf9f5a13ccfd3127858aa501 + +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/filezilla-kasm/logo.png b/apps/filezilla-kasm/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..9837029d897e0734b0e2e22b9ed8051415f77292 GIT binary patch literal 9260 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 AcmMzZ literal 0 HcmV?d00001