Initialize Clash Web source and deployment documentation
This commit is contained in:
commit
8e0fa00a73
66 files changed
+8532
No files matched your search
@@ -0,0 +1,119 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Package already-built Linux amd64 resources; never include runtime state."""
|
||||
import argparse
|
||||
import datetime
|
||||
import hashlib
|
||||
import json
|
||||
import subprocess
|
||||
import tarfile
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
|
||||
root = Path(__file__).resolve().parent.parent
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument('--output-dir', type=Path, default=root)
|
||||
args = parser.parse_args()
|
||||
args.output_dir.mkdir(parents=True, exist_ok=True)
|
||||
(root / '.cache').mkdir(exist_ok=True)
|
||||
|
||||
def digest(path):
|
||||
return hashlib.sha256(path.read_bytes()).hexdigest()
|
||||
|
||||
for name in ('clashweb', 'mihomo'):
|
||||
header = (root / 'bin' / name).read_bytes()[:64]
|
||||
if header[:5] != b'\x7fELF\x02' or int.from_bytes(header[18:20], 'little') != 62:
|
||||
raise SystemExit(f'bin/{name} must be a Linux amd64 ELF binary')
|
||||
|
||||
update_readme = '''# Clash Web 管理程序更新(Linux amd64)
|
||||
|
||||
本包更新 Clash Web 管理服务及其嵌入的 Web UI。
|
||||
无需更新 Mihomo 或规则,也不修改数据库、管理员密码、订阅和 VM 网络设置。
|
||||
|
||||
在已部署的目标 VM 上解压并进入本目录,然后执行:
|
||||
|
||||
```bash
|
||||
sha256sum -c SHA256SUMS
|
||||
sudo install -m 0755 -o root -g root /usr/local/bin/clashweb /usr/local/bin/clashweb.previous
|
||||
sudo install -m 0755 -o root -g root bin/clashweb /usr/local/bin/clashweb.next
|
||||
sudo mv /usr/local/bin/clashweb.next /usr/local/bin/clashweb
|
||||
sudo systemctl restart clashweb
|
||||
sudo systemctl status clashweb --no-pager
|
||||
```
|
||||
|
||||
重启后刷新浏览器,确认管理服务正常。独立 Mihomo 内核继续运行;若页面仍显示旧内容,可用 Ctrl+Shift+R 刷新。
|
||||
|
||||
需要回退时执行:
|
||||
|
||||
```bash
|
||||
sudo install -m 0755 -o root -g root /usr/local/bin/clashweb.previous /usr/local/bin/clashweb.rollback
|
||||
sudo mv /usr/local/bin/clashweb.rollback /usr/local/bin/clashweb
|
||||
sudo systemctl restart clashweb
|
||||
```
|
||||
|
||||
测试只检查 HTTPS 主页,不承诺流媒体解锁、AI 账号或镜像拉取。
|
||||
完整说明见 docs/upgrading.md。
|
||||
'''
|
||||
|
||||
deploy_readme = '''# Clash Web Linux amd64 部署包
|
||||
|
||||
包含静态 Go 管理程序与 Web UI、Mihomo v1.19.32、已有大陆规则、安装脚本和文档。
|
||||
在正式 PVE VM 上部署;不包含任何订阅、管理员密码或开发机运行数据。
|
||||
|
||||
解压后进入目录,先运行 `sha256sum -c SHA256SUMS`。
|
||||
首次安装见 docs/deployment.md;Ubuntu/Debian 需要 sudo、python3、iproute2、nftables、ca-certificates。
|
||||
运行 `sudo scripts/install.sh --target-vm --bind VM_IP:8080`。
|
||||
VM 固定 IP、转发、防火墙与客户端网关/DNS 按部署文档配置,VM 不运行 DHCP。
|
||||
|
||||
已经部署的 VM 推荐使用 clashweb-update-linux-amd64.tar.gz,只替换管理程序。
|
||||
不要用包内空数据覆盖 /var/lib/clashweb 或 /var/lib/clashweb-core。
|
||||
'''
|
||||
|
||||
scripts = ['install.sh', 'clashweb-control', 'network-vm.py', 'fetch-mihomo.py',
|
||||
'fetch-rules.py', 'update-rules.sh', 'diagnose-subscription.py']
|
||||
with tempfile.TemporaryDirectory(prefix='package-', dir=root / '.cache') as temp:
|
||||
for name, full in [('clashweb-linux-amd64', True), ('clashweb-update-linux-amd64', False)]:
|
||||
stage = Path(temp) / name
|
||||
files = ['bin/clashweb']
|
||||
if full:
|
||||
files += ['bin/mihomo', 'data/mihomo/rules/cn-domain.mrs', 'data/mihomo/rules/cn-ip.mrs']
|
||||
files += ['scripts/' + script for script in scripts]
|
||||
files += [p.relative_to(root).as_posix() for p in (root / 'deploy').glob('*.service')]
|
||||
files += ['README.md']
|
||||
files += ['docs/' + document for document in ['api.md', 'development.md', 'deployment.md', 'upgrading.md', 'third-party.md']]
|
||||
else:
|
||||
files += ['docs/upgrading.md']
|
||||
for relative in files:
|
||||
destination = stage / relative
|
||||
destination.parent.mkdir(parents=True, exist_ok=True)
|
||||
shutil.copy2(root / relative, destination)
|
||||
(stage / 'README-DEPLOY.md' if full else stage / 'README-UPDATE.md').write_text(deploy_readme if full else update_readme)
|
||||
(stage / 'BUILD-INFO.json').write_text(json.dumps({
|
||||
'platform': 'linux/amd64', 'goamd64': 'v1', 'cgoEnabled': False,
|
||||
'createdAt': datetime.datetime.now(datetime.timezone.utc).isoformat(),
|
||||
'clashwebSha256': digest(root / 'bin/clashweb'),
|
||||
'mihomoVersion': 'v1.19.32' if full else None,
|
||||
}, indent=2) + '\n')
|
||||
payload = sorted(p for p in stage.rglob('*') if p.is_file())
|
||||
(stage / 'SHA256SUMS').write_text(''.join(f'{digest(p)} {p.relative_to(stage).as_posix()}\n' for p in payload))
|
||||
archive = args.output_dir / f'{name}.tar.gz'
|
||||
with tarfile.open(archive, 'w:gz') as tar:
|
||||
for p in sorted(stage.rglob('*')):
|
||||
if p.is_file():
|
||||
tar.add(p, arcname=name + '/' + p.relative_to(stage).as_posix(), recursive=False)
|
||||
archive.with_suffix(archive.suffix + '.sha256').write_text(f'{digest(archive)} {archive.name}\n')
|
||||
# Verify the actual archive, not just its staging directory.
|
||||
with tarfile.open(archive) as tar:
|
||||
extracted = Path(temp) / (name + '-verify')
|
||||
tar.extractall(extracted, filter='data')
|
||||
checked = subprocess.run(['sha256sum', '-c', 'SHA256SUMS'], cwd=extracted / name, capture_output=True)
|
||||
if checked.returncode:
|
||||
raise SystemExit('Package payload checksum failed')
|
||||
if full:
|
||||
clean = Path(temp) / 'clean-init'
|
||||
initialized = subprocess.run([str(extracted / name / 'bin/clashweb'), '--init',
|
||||
'--data', str(clean / 'app'), '--core-dir', str(extracted / name / 'data/mihomo'),
|
||||
'--mihomo', str(extracted / name / 'bin/mihomo')], capture_output=True)
|
||||
if initialized.returncode:
|
||||
raise SystemExit('Clean package initialization/core validation failed')
|
||||
print(f'{archive}: {archive.stat().st_size:,} bytes, payload checksums verified')
|
||||
Reference in new issue
Block a user