Skip to content
Jonnyan404Public

About

Self-hosted cross-device clipboard and file transfer. Rust server, single binary, no database.

Resources

Stars

1 star

Watchers

1 watching

Forks

Repository files navigation

clip9

release downloads license Rust Android

自托管的跨设备剪贴板 —— 文本、图片、文件在手机、电脑、路由器之间实时互传。
Rust 重写自 cloud-clipboard-go,数据完全握在自己手里。


📸 界面截图

💻 桌面端

桌面端

🌐 网页端

网页端

📱 手机

手机


🎯 亮点

特性 说明
🔒 隐私安全 部署在自己的机器或服务器上,数据不经过任何第三方
📦 部署灵活 一个静态二进制同时供应 Docker、裸机、OpenWrt 与 Android;另有 Cloudflare Serverless 一路
🌍 跨平台 服务端覆盖 Linux / macOS / Windows / ARM 路由;客户端有桌面端、Android 与快捷指令
⚡ 实时同步 WebSocket 双向广播,历史走 HTTP 分页拉取(只推实时、不推全量)
🔐 认证保护 全局密码、按房间独立密码、可续期的会话令牌、带密码的分享链接
🎨 多种界面模式 时间流 / 速览 / 便签 / 看板等;?mode= 让同一个浏览器标签页锁定一种模式
🧩 动作库 一条内容换个方式看:Markdown、JSON 美化、编解码、注音、日期计算、哈希…… 还能串成流水线
⏰ 定时自动化 按每天 / 每周 / 仅一次 / 5 字段 cron 把渲染好的文本投进房间,正文支持模板变量
🔗 分享链接 单条内容的短期链接,可限次数、可带密码,分享页自动注入 OG 卡片
🪶 轻量 内存与体积都很小,16 MB flash 的路由器也能跑

🚀 快速开始

服务端默认监听 9501。装好之后浏览器打开 http://<服务器地址>:9501 就是界面。

🐳 Docker(推荐)

docker run -d \
  --name clip9 \
  --init \
  -p 9501:9501 \
  -v /path/to/data:/app/server-node/data \
  ghcr.io/jonnyan404/clip9:latest

⚠️ --init 是必须的:服务端没有装 SIGTERM 处理器,而 PID 1 对没有处理函数的信号是内核直接忽略的。 不加它,docker stop 要等满 10 秒超时才被 SIGKILL;加上之后实测 0.22 秒。

⚠️ latest 只在正式发布时才有;预发布只推 vX.Y.Z,要用 beta 就写全版本号。

docker-compose.yml

仓库根目录自带一份,写法与 Go 版一致:

services:
  clip9:
    container_name: clip9
    restart: always
    init: true
    ports:
      - "9501:9501"
    environment:
      # 监听
      LISTEN_IP: ${LISTEN_IP:-}                # 监听地址,默认 0.0.0.0
      LISTEN_IP6: ${LISTEN_IP6:-}              # IPv6 地址(如 ::),默认不监听
      LISTEN_PORT: ${LISTEN_PORT:-}            # 监听端口,默认 9501
      PREFIX: ${PREFIX:-}                      # URL 子路径(配合 nginx),如 /clip9
      # 访问控制
      AUTH_PASSWORD: ${AUTH_PASSWORD:-}        # 全局访问密码,留空即无需密码
      ROOM_AUTH_JSON: '${ROOM_AUTH_JSON:-{}}'  # 房间密码 JSON,如 {"finance":"finance-pass"}
      ROOM_LIST: ${ROOM_LIST:-}                # 是否公开房间列表,默认 false
      # 容量
      MESSAGE_NUM: ${MESSAGE_NUM:-}            # 历史保留条数,默认 50
      TEXT_LIMIT: ${TEXT_LIMIT:-}              # 文本长度上限(字节),默认 4096
      FILE_EXPIRE: ${FILE_EXPIRE:-}            # 文件过期秒数,默认 3600
      FILE_LIMIT: ${FILE_LIMIT:-}              # 文件大小上限(字节),默认 104857600
      # 定时自动化
      AUTOMATION_ENABLED: ${AUTOMATION_ENABLED:-}  # 总开关,默认 true
      DEFAULT_TZ: ${DEFAULT_TZ:-}              # 默认时区,默认 Asia/Shanghai
      # TLS —— 优先级:手动路径 > mkcert > 不启用
      MANUAL_KEY_PATH: ${MANUAL_KEY_PATH:-}    # 手动指定私钥路径(优先级最高)
      MANUAL_CERT_PATH: ${MANUAL_CERT_PATH:-}  # 手动指定证书路径
      MKCERT_DOMAIN_OR_IP: ${MKCERT_DOMAIN_OR_IP:-}  # 填域名/IP 即自动签自签证书,多个用空格分隔
    volumes:
      - /path/your/dir/data:/app/server-node/data  # 改成你自己的目录
    image: ghcr.io/jonnyan404/clip9:latest

变量名与 Go 版完全一致,切过来不用改。上面这份就是全部(仓库根的 docker-compose.yml 还带一个 healthcheck)。 ⚠️ 直接跑二进制时也可以用环境变量,名字是 CLIP9_ + 参数名大写(CLIP9_PORT / CLIP9_CONFIG …)—— 这是本实现额外加的,Go 版没有。

docker compose up -d

📦 其他装法

1️⃣ 独立二进制(Linux / macOS / Windows)

从 Releases 下载对应平台的文件:

./clip9-cli -port 9501 -auth mypassword123

常用参数:-host / -port / -auth / -config / -static,全部见 --help。

2️⃣ OpenWrt 路由器
cat /etc/apk/arch                                  # 先看架构

apk add --allow-untrusted ./clip9-<版本>-<架构>.apk   # OpenWrt 25.12+
opkg install ./clip9_<版本>_<架构>.ipk                # OpenWrt 24.10 及更早

装完在 LuCI 里配置。

3️⃣ Android 手机当服务器

从 Releases 装 .apk,打开后设端口/密码、点「启动服务」, 局域网里任何设备访问 http://手机IP:9501 即可。

4️⃣ Cloudflare Workers(Serverless)

基于 Workers + D1 + R2,支持 GitHub Actions 自动部署或本地脚本部署。 详见 Cloudflare 部署指南。

5️⃣ 从源码构建

前置:Node.js ≥ 22、Rust stable。

cd web && npm install && npm run build    # 前端产物
node tools/sync-web-assets.mjs            # 同步进 rust/crates/server/static/(会被编进二进制)
cd rust && cargo build --release -p clip9-server

⚠️ cargo 只能在 rust/ 里跑 —— 仓库根没有 Cargo.toml。


⚙️ 配置

服务端读一个 JSON 配置文件(默认 config.json,不存在时自动生成一份默认的)。Docker 与 OpenWrt 下由入口脚本生成。

配置字段一览
{
  "server": {
    "host": ["0.0.0.0"], "port": 9501, "prefix": "",
    "history": 50, "dbPath": "clip9.redb", "storageDir": "uploads",
    "auth": false, "roomAuth": {}, "cert": "", "key": "",
    "roomList": false, "roomCleanup": 3600
  },
  "text": { "limit": 4096 },
  "file": { "expire": 3600, "chunk": 1048576, "limit": 268435456 },
  "automation": { "enabled": true, "tickSeconds": 30, "graceSeconds": 600, "defaultTZ": "Asia/Shanghai" }
}

ℹ️ 环境变量名与命令行参数名都与 Go 版逐一对齐,换过来通常只需要改 Docker 的 image 那一行。


🔄 从 Go 版迁移

一条子命令把 Go 的 history.json 与 uploads/ 搬进数据库。原始数据一个字节都不动(回退的唯一依据),重复跑不会重复导入。

clip9-cli migrate -from /旧的数据目录 -dry-run   # 先试运行:只读、只报告
clip9-cli migrate -from /旧的数据目录            # 确认无误再真跑

⚠️ 必须在服务停着的时候跑(redb 独占锁)—— 这也正是它做成子命令、而不是「首次启动自动导入」的原因。

细节
  • 迁:history.json 的 receive → 消息表、file → 文件登记表、uploads/<uuid> → 原样拷。 不迁 share-log.json(短期)与 tasks.json(是配置,不是数据)。

  • 幂等:重复跑跳过已存在的 id。⚠️ 重插会让房间计数 +1(/rooms 上直接看得出)。

  • 源不动:工具只读 Go 那边的目录 —— 要删请你自己确认之后再删。

  • Docker:数据目录与 Go 版是同一个,卷不用改;但入口脚本不接受参数,要覆盖 entrypoint:

    docker stop clip9
    docker run --rm --entrypoint /app/server-node/clip9-cli \
      -v /你的/data:/app/server-node/data ghcr.io/jonnyan404/clip9:latest \
      migrate -from /app/server-node/data -dry-run
    docker start clip9
  • ⚠️ config.json 必须是严格 JSON(Go 那份带 # 注释)—— 解析失败直接退出。这是刻意的: Go 会打一行日志、然后用默认值继续跑,那等于一个拼错的配置让服务不带密码地起来。


🌐 API

curl http://localhost:9501/content/latest          # 最新一条
curl "http://localhost:9501/content?room=work"     # 某个房间的历史

🗂️ 项目结构

展开
目录 是什么
rust/crates/server HTTP + WebSocket 服务端(前端产物编在里面)
rust/crates/client 连接与同步逻辑(桌面端与 SPA 共用一份契约)
rust/crates/core 纯逻辑:配置、动作库、统计、协议类型
rust/crates/store 存储(redb)
rust/crates/desktop Tauri 桌面端
web/ 网页界面(React + Vite)
android/ Android 外壳(Kotlin)
cloudflare/ Workers + D1 + R2 那一路
openwrt/ 路由器打包与 LuCI 插件
shortcuts/ Apple / Android 快捷指令

🤝 贡献

欢迎 Issue 与 PR。提交前请跑门禁(零警告是硬要求):

cd rust
cargo fmt --all
cargo clippy --workspace --all-targets -- -D warnings
cargo test  --workspace

ℹ️ 仓库里有一份内部的工程约定与设计稿(dev-docs/),它刻意不入库 —— 里面混着工作过程记录。 所以代码注释里会看到 见 dev-docs/… 这类指针,对只拿到仓库的人来说那些指向的是不存在的东西, 这是有意的取舍。


📄 许可证与致谢

基于 MIT License 开源。

前端与后端最初 fork 自 TransparentLC/cloud-clipboard 与 yurenchen000/cloud-clipboard, 以及它的 Go 前身 Jonnyan404/cloud-clipboard-go。


☕ 支持项目

如果这个项目帮到了你,欢迎 ⭐ Star,或通过以下方式支持我们:

💰 赞赏捐助

你的支持是我们继续维护和改进项目的动力!

方式 二维码
微信 微信赞赏码

🌟 其他支持方式

About

Self-hosted cross-device clipboard and file transfer. Rust server, single binary, no database.

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages