ClipCascade 安装部署指南

Ubuntu 22.04 裸机部署 ClipCascade 服务端 v3.3.1 全流程实测:Java 21 环境、专用账户、systemd 单元、首次登录改密闭环、nginx HTTPS+WebSocket 反向代理与排障速查。

ClipCascade剪贴板同步Java平台信息安全2026/10/28

ClipCascade 安装部署指南

本文在 Ubuntu 22.04 服务器上以 systemd 裸机方式部署 ClipCascade 服务端 v3.3.1,覆盖 Java 21 环境、专用系统账户、环境变量文件、开机自启、HTTPS 反向代理与首次登录加固全流程。文中全部命令与回显均在真实服务器上逐条实测。

选型背景与产品定位见 《ClipCascade 介绍与选型指南》;部署完成后要精细化调整服务端行为,请转到 《ClipCascade 配置参数详解》;日常运维与客户端命令行见 《ClipCascade 常用 CLI 命令详解》。

一、部署规划

项目本文取值说明
操作系统Ubuntu 22.04(64 位)服务端只依赖 Java 21+,其他发行版同理
服务端版本v3.3.1官方 Releases 最新稳定版(发布于 2026-10-25)
运行账户clipcascade(系统用户,无登录 shell)最小权限运行
安装目录/opt/clipcascade存放服务端 JAR
数据目录/var/lib/clipcascade工作目录,内含数据库 database/ 与日志 logs/
配置文件/etc/clipcascade/clipcascade.envsystemd EnvironmentFile
监听端口8080(HTTP 服务)由 CC_PORT 控制,本文另配 nginx 443 对外
默认管理员admin / admin123首次登录后必须立即修改(本文实测演示)

服务端形态说明:官方对外分发的服务端产物是一个独立 JAR(ClipCascade-Server-JRE_21.jar),内嵌 Web 服务与 WebSocket 端点,任意满足 Java 21+ 的环境可直接运行;官方仓库另附带打包部署样例文件供偏好的读者取用,但本文遵循裸机 + systemd 的生产服务器视角展开。

二、安装 Java 21

ClipCascade 服务端要求 Java 21 或更高版本。Ubuntu 22.04 官方源即可满足:

apt update
apt install -y openjdk-21-jre-headless
java -version

实测回显:

openjdk version "21.0.12.1" 2026-08-18
OpenJDK Runtime Environment (build 21.0.12.1+1-1-22.04.4-Ubuntu)
OpenJDK 64-Bit Server VM (build 21.0.12.1+1-22.04.4-Ubuntu, mixed mode, sharing)

三、创建运行账户与目录

useradd --system --home-dir /var/lib/clipcascade --create-home --shell /usr/sbin/nologin clipcascade
mkdir -p /opt/clipcascade /etc/clipcascade
mkdir -p /var/lib/clipcascade/database /var/lib/clipcascade/logs
chown -R clipcascade:clipcascade /var/lib/clipcascade

说明:数据库目录 /var/lib/clipcascade/database 用于存放内置 H2 数据库文件(默认加密),日志目录存放滚动日志。若后续切换 PostgreSQL,可将两者迁移至独立存储。

四、下载服务端 JAR

从官方 GitHub Releases 下载 v3.3.1 的服务端包(网络受限环境可为下载命令追加代理参数,如 -x http://192.168.1.62:7897):

cd /opt/clipcascade
curl -L -o ClipCascade-Server-JRE_21.jar \
  https://github.com/Sathvik-Rao/ClipCascade/releases/download/v3.3.1/ClipCascade-Server-JRE_21.jar
ls -l ClipCascade-Server-JRE_21.jar

实测回显:

-rw-r--r-- 1 root root 77894246 Oct 28 03:34 ClipCascade-Server-JRE_21.jar

JAR 约 74 MiB,为内置 JRE 21 目标的自包含服务端。若官方发布页后续提供 SHA256 校验值,建议下载后核对。

五、编写环境变量文件

ClipCascade 的全部服务端行为通过 CC_ 前缀环境变量控制,均非必填(不配置则走内置默认值)。本文先落一份贴近默认值的基础配置:

cat > /etc/clipcascade/clipcascade.env <<'EOF'
CC_PORT=8080
CC_MAX_MESSAGE_SIZE_IN_MiB=1
CC_P2P_ENABLED=false
CC_SIGNUP_ENABLED=false
CC_ALLOWED_ORIGINS=*
CC_SESSION_TIMEOUT=525960m
CC_SERVER_LOGGING_LEVEL=INFO
EOF
chown root:clipcascade /etc/clipcascade/clipcascade.env
chmod 640 /etc/clipcascade/clipcascade.env

逐项含义与更多变量(数据库、防暴力破解、外部消息代理等共 37 个)见 《ClipCascade 配置参数详解》。此处两点安全取向:

  • CC_SIGNUP_ENABLED=false:关闭自助注册,用户一律由管理员创建,防止公共实例被陌生人占用;
  • CC_ALLOWED_ORIGINS:若有固定域名,建议改为 https://clipcascade.example.com 收紧 WebSocket 跨域。

六、编写 systemd 单元

cat > /etc/systemd/system/clipcascade.service <<'EOF'
[Unit]
Description=ClipCascade Clipboard Sync Server
After=network.target

[Service]
Type=simple
User=clipcascade
Group=clipcascade
WorkingDirectory=/var/lib/clipcascade
EnvironmentFile=/etc/clipcascade/clipcascade.env
ExecStart=/usr/bin/java -Xms256m -Xmx512m -jar /opt/clipcascade/ClipCascade-Server-JRE_21.jar
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable --now clipcascade

实测要点:-Xms256m -Xmx512m 将堆内存限制在 512MB,单人/小团队规模绰绰有余(实测进程常驻内存约 400MB);WorkingDirectory 指向 /var/lib/clipcascade,使相对路径的 H2 数据库落在 ./database/ 下。

启动后确认状态:

systemctl status clipcascade --no-pager -l

实测回显(节选):

● clipcascade.service - ClipCascade Clipboard Sync Server
     Loaded: loaded (/etc/systemd/system/clipcascade.service; enabled; vendor preset: enabled)
     Active: active (running) since Wed 2026-10-28 03:35:28 UTC; 25min ago
   Main PID: 4006 (java)
      Tasks: 49 (limit: 2932)
     Memory: 398.2M
        CPU: 13.654s
     CGroup: /system.slice/clipcascade.service
             └─4006 /usr/bin/java -Xms256m -Xmx512m -jar /opt/clipcascade/ClipCascade-Server-JRE_21.jar

观察启动日志确认内嵌 Web 服务就绪:

journalctl -u clipcascade -n 5 --no-pager -o cat

实测回显(节选):

2026-10-28T04:05:22.313Z  INFO 4773 --- [ClipCascade] [           main] c.a.clipcascade.ClipCascadeApplication   : Started ClipCascadeApplication in 3.405 seconds (process running for 3.69)
2026-10-28T04:05:26.656Z  INFO 4773 --- [ClipCascade] [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2026-10-28T04:05:26.657Z  INFO 4773 --- [ClipCascade] [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 1 ms

冷启动到可用约 4 秒。

七、健康检查与版本核实

ClipCascade 内置两个免认证探活端点:

curl -s http://127.0.0.1:8080/health; echo
curl -s http://127.0.0.1:8080/ping; echo

实测回显:

OK
pong

再核实服务端自报版本:

curl -s http://127.0.0.1:8080/server-version; echo

实测回显:

{"version":"3.3.0"}

排障实录:/server-version 与发布版本不一致 现象:从 Releases 下载的是 v3.3.1 包,/server-version 却自报 3.3.0。 原因:服务端界面/API 的版本常量随构建打入,可能滞后于发布标签(官方 API 文档也明确提示"deployed builds may differ")。 结论:判断真实版本以下载来源的 Release 标签为准,/server-version 只能作为参考;该差异不影响功能与 API 兼容性。

八、首次登录与立即改密

浏览器访问 http://<服务器IP>:8080(经反代后为你的 HTTPS 域名),默认凭据登录:

  • 用户名:admin
  • 密码:admin123

登录页默认开启 CAPTCHA,输入验证码后进入控制面板。官方强烈建议首次登录后立即修改默认口令,本文以新建账号演示完整的"首登—改密—旧口令失效"闭环(管理员 admin 在本实验机已按同样流程改密为 q1w2e3r4)。

登录协议细节:客户端提交的密码是原始口令的 SHA3-512 小写十六进制摘要(服务端再以 BCrypt 落库)。这正是下文脚本对密码先做摘要再提交的原因——直接提交明文也能建号,但会与官方客户端的登录约定不兼容。

第一步:管理员创建测试账号 user2,初始口令 admin123:

# cc_chgpass.py —— 首登改密闭环实测
import hashlib
import json
from html.parser import HTMLParser
from urllib.parse import urlsplit
import requests

class CsrfParser(HTMLParser):
    token = None
    def handle_starttag(self, tag, attrs):
        attrs = dict(attrs)
        if tag == "input" and attrs.get("name") == "_csrf":
            self.token = attrs.get("value")

base = "http://localhost:8080"

def sha3(raw):
    return hashlib.sha3_512(raw.encode("utf-8")).hexdigest()

def login(user, pwd):
    s = requests.Session()
    p = CsrfParser()
    p.feed(s.get(base + "/login", timeout=15).text)
    r = s.post(base + "/login", data={"username": user, "password": sha3(pwd), "_csrf": p.token},
               allow_redirects=False, timeout=15)
    print(f"login {user} -> {r.status_code} {r.headers.get('Location', '')}")
    assert r.status_code == 302 and urlsplit(r.headers.get("Location", "")).path == "/"
    return s

admin = login("admin", "q1w2e3r4")
csrf = admin.get(base + "/csrf-token", timeout=15).json()
admin.headers[csrf["headerName"]] = csrf["token"]
r = admin.post(base + "/admin/register-user",
               json={"username": "user2", "password": sha3("admin123"), "role": "USER", "enabled": True},
               timeout=15)
print("create user2:", r.status_code, r.text)

实测回显:

login admin -> 302 http://localhost:8080/
create user2: 200 User registered successfully

第二步:user2 用初始口令登录并改密为 q1w2e3r4:

u2 = login("user2", "admin123")
print("whoami:", json.dumps(u2.get(base + "/whoami", timeout=15).json()))
csrf2 = u2.get(base + "/csrf-token", timeout=15).json()
u2.headers[csrf2["headerName"]] = csrf2["token"]
r = u2.put(base + "/update-password", json={"newPassword": sha3("q1w2e3r4")}, timeout=15)
print("PUT /update-password ->", r.status_code, r.text)

实测回显:

login user2 -> 302 http://localhost:8080/
whoami: {"role": "USER", "username": "user2"}
PUT /update-password -> 200 Password updated successfully

第三步:验证旧口令立即失效、新口令可登录:

s = requests.Session()
p = CsrfParser()
p.feed(s.get(base + "/login", timeout=15).text)
r = s.post(base + "/login", data={"username": "user2", "password": sha3("admin123"), "_csrf": p.token},
           allow_redirects=False, timeout=15)
print("old pwd login ->", r.status_code, r.headers.get("Location", ""))
login("user2", "q1w2e3r4")

实测回显:

old pwd login -> 302 http://localhost:8080/login?error
login user2 -> 302 http://localhost:8080/
re-login with new password ok

改密即时生效,无需重启服务;被修改账号的既有会话与 WebSocket 连接会被服务端自动吊销。

创建正式用户的两种方式:一是管理面板 Users 页面点 Add User(填用户名/初始口令/角色);二是上文所示 POST /admin/register-user API。重复创建同名账号会失败:

POST /admin/register-user -> 400 User already exists or invalid user

另外,CC_SIGNUP_ENABLED=false 时自助注册页被整体关闭:访问 /signup 会直接 302 跳回首页(实测回显:signup redirect -> http://127.0.0.1:8080/)。

九、nginx 反向代理(HTTPS + WebSocket)

生产环境建议统一走 HTTPS 域名入口。ClipCascade 有两个 WebSocket 握手端点(P2S 的 /clipsocket 与 P2P 的 /p2psignaling),反代必须为它们配置 HTTP/1.1 升级头,否则客户端能登录但剪贴板不流动。

server {
    listen 80;
    server_name _;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    server_name _;

    ssl_certificate     /etc/nginx/ssl/clipcascade.crt;
    ssl_certificate_key /etc/nginx/ssl/clipcascade.key;
    ssl_protocols       TLSv1.2 TLSv1.3;

    client_max_body_size 128m;

    location / {
        proxy_pass         http://127.0.0.1:8080;
        proxy_set_header   Host $host;
        proxy_set_header   X-Real-IP $remote_addr;
        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Proto $scheme;
    }

    location /clipsocket {
        proxy_pass http://127.0.0.1:8080;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_read_timeout 3600s;
        proxy_send_timeout 3600s;
    }

    location /p2psignaling {
        proxy_pass http://127.0.0.1:8080;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_read_timeout 3600s;
        proxy_send_timeout 3600s;
    }
}

三个容易踩的坑:

  1. client_max_body_size:nginx 默认 1MiB,会先于服务端拦下超限的图片/文件消息,需与 CC_MAX_MESSAGE_SIZE_IN_MiB 联动放大(上文取 128m)。
  2. proxy_read_timeout:长连接心跳间隔约 20 秒,默认 60 秒读超时会让空闲连接频繁重建,建议 3600s 起。
  3. 通配证书:若走 Cloudflare Tunnel 等隧道,WebSocket 同样开箱即用,无需额外配置(官方 README 确认)。

十、客户端接入(Linux 侧速览)

各平台客户端在官方 Releases 页下载:Windows MSI、macOS 双架构 ZIP、Android APK;Linux 提供源码包 ClipCascade_Linux.zip(含 GUI 托盘与终端 CLI 双形态)。客户端登录时填服务器地址与端口,端到端加密默认开启——所有设备保持一致的加密开关、盐值与迭代数(默认迭代 664937、盐为空)。

Linux 客户端依赖安装中有一个著名的命名空间坑:发行版仓库装的 python3-pycryptodomex 提供的是 Cryptodome 命名空间,而客户端代码 import Crypto,首次启动会报 ModuleNotFoundError: No module named 'Crypto'。修复办法是为它建一个软链接(完整排障过程见 《ClipCascade 常用 CLI 命令详解》排障实录一节):

ln -s /usr/lib/python3/dist-packages/Cryptodome /usr/lib/python3/dist-packages/Crypto

启动参数(--gui、--xmode、--polling)与日常使用命令同样在 CLI 篇展开。若还需要文件级多机同步,可搭配 《Ubuntu 22.04 安装 Syncthing 指南》。

十一、升级与回滚

  1. 停服:systemctl stop clipcascade;
  2. 备份当前 JAR 与数据:cp /opt/clipcascade/ClipCascade-Server-JRE_21.jar{,.bak} 与 cp -a /var/lib/clipcascade/database /var/lib/clipcascade/database.bak;
  3. 下载新版本 JAR 覆盖 /opt/clipcascade/;
  4. systemctl start clipcascade 后看 journalctl -u clipcascade -f 与 /health;
  5. 回滚即恢复 .bak 文件重启。数据库加密口令(CC_SERVER_DB_PASSWORD)在版本间保持不变,勿在升级时顺手修改。

十二、卸载

systemctl disable --now clipcascade
rm /etc/systemd/system/clipcascade.service && systemctl daemon-reload
rm -rf /opt/clipcascade /etc/clipcascade /var/lib/clipcascade
userdel clipcascade

数据目录删除前如需留档,先打包 /var/lib/clipcascade/database。

十三、排障速查

现象诊断处置
systemctl start 后 /health 不通journalctl -u clipcascade -n 50 看是否 Java 版本低于 21安装 openjdk-21-jre-headless
改了 clipcascade.env 不生效环境变量在进程启动时读取systemctl restart clipcascade 后复查
8080 被其他进程占用`ss -ltnpgrep 8080`
登录一直 302 /login?error口令错误或 BFA 锁定查 /admin/bfa-snapshot(管理员),确认锁定时间;默认单 IP 失败 30 次锁 60 秒
能登录但剪贴板不同步反代未放行 WebSocket 升级检查 /clipsocket 的 Upgrade/Connection 头与 proxy_read_timeout
大图片/文件发送失败nginx 或服务端任一处限值过小调大 client_max_body_size 与 CC_MAX_MESSAGE_SIZE_IN_MiB

更多日常运维命令与客户端 CLI,见 《ClipCascade 常用 CLI 命令详解》。