vault backup: 2025-12-29 13:52:38
This commit is contained in:
Vendored
+13
-10
@@ -4,17 +4,21 @@
|
|||||||
"type": "split",
|
"type": "split",
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"id": "9e7e27783759b32f",
|
"id": "535cd3aee7a6c27d",
|
||||||
"type": "tabs",
|
"type": "tabs",
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"id": "2f3ad4ca52c735ee",
|
"id": "e7acd6d53c22af38",
|
||||||
"type": "leaf",
|
"type": "leaf",
|
||||||
"state": {
|
"state": {
|
||||||
"type": "empty",
|
"type": "markdown",
|
||||||
"state": {},
|
"state": {
|
||||||
|
"file": "2025-12-29.md",
|
||||||
|
"mode": "source",
|
||||||
|
"source": false
|
||||||
|
},
|
||||||
"icon": "lucide-file",
|
"icon": "lucide-file",
|
||||||
"title": "New tab"
|
"title": "2025-12-29"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -250,8 +254,11 @@
|
|||||||
"smart-connections:Smart Connections: Open random connection": false
|
"smart-connections:Smart Connections: Open random connection": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"active": "2f3ad4ca52c735ee",
|
"active": "ec72abdaaa8e91a6",
|
||||||
"lastOpenFiles": [
|
"lastOpenFiles": [
|
||||||
|
"2025-12-29.md",
|
||||||
|
"Untitled.base",
|
||||||
|
"Untitled 1.base",
|
||||||
"100-project/Personal/VPS/hk2.chans.xyz.md",
|
"100-project/Personal/VPS/hk2.chans.xyz.md",
|
||||||
"000-inbox/clippings/2024/12/GitHub - DubhAdHome-AssistantConfig My Home Assistant configuration files.md",
|
"000-inbox/clippings/2024/12/GitHub - DubhAdHome-AssistantConfig My Home Assistant configuration files.md",
|
||||||
"100-project/Personal/VPS/https proxy.md",
|
"100-project/Personal/VPS/https proxy.md",
|
||||||
@@ -279,8 +286,6 @@
|
|||||||
"100-project/Personal/AI/Kiro/in-memoria.md",
|
"100-project/Personal/AI/Kiro/in-memoria.md",
|
||||||
"100-project/Personal/AI/Kiro",
|
"100-project/Personal/AI/Kiro",
|
||||||
"100-project/Personal/AI/mcp.md",
|
"100-project/Personal/AI/mcp.md",
|
||||||
"100-project/Personal/AI/DeepSeek.md",
|
|
||||||
"100-project/Personal/AI/AutoGPT.md",
|
|
||||||
"100-project/Personal/Hardware/Home Assistant",
|
"100-project/Personal/Hardware/Home Assistant",
|
||||||
"ReadItLater Inbox/assets/math.png",
|
"ReadItLater Inbox/assets/math.png",
|
||||||
"ReadItLater Inbox/assets/medal.png",
|
"ReadItLater Inbox/assets/medal.png",
|
||||||
@@ -292,8 +297,6 @@
|
|||||||
"Pasted image 20240909145917.png",
|
"Pasted image 20240909145917.png",
|
||||||
"100-project/Personal/resume",
|
"100-project/Personal/resume",
|
||||||
"copilot/copilot-conversations",
|
"copilot/copilot-conversations",
|
||||||
"copilot/copilot-custom-prompts",
|
|
||||||
"copilot",
|
|
||||||
"ReadItLater Inbox/assets/elec.png",
|
"ReadItLater Inbox/assets/elec.png",
|
||||||
"ReadItLater Inbox/assets/Menu-1.png",
|
"ReadItLater Inbox/assets/Menu-1.png",
|
||||||
"ReadItLater Inbox/assets/bike-1.png",
|
"ReadItLater Inbox/assets/bike-1.png",
|
||||||
|
|||||||
@@ -16,3 +16,34 @@
|
|||||||
"event_logs:blocks:cleaned": {"key":"blocks:cleaned","ct":1,"first_at":1766986882899,"last_at":1766986882899,"class_name":"EventLog"},
|
"event_logs:blocks:cleaned": {"key":"blocks:cleaned","ct":1,"first_at":1766986882899,"last_at":1766986882899,"class_name":"EventLog"},
|
||||||
"event_logs:event_log:first": {"key":"event_log:first","ct":12,"first_at":1766986874718,"last_at":1766986884103,"class_name":"EventLog"},
|
"event_logs:event_log:first": {"key":"event_log:first","ct":12,"first_at":1766986874718,"last_at":1766986884103,"class_name":"EventLog"},
|
||||||
"event_logs:connections:opened": {"key":"connections:opened","ct":2,"first_at":1766986884102,"last_at":1766986884117,"class_name":"EventLog"},
|
"event_logs:connections:opened": {"key":"connections:opened","ct":2,"first_at":1766986884102,"last_at":1766986884117,"class_name":"EventLog"},
|
||||||
|
"event_logs:event_log:first": {"key":"event_log:first","ct":13,"first_at":1766986874718,"last_at":1766987075389,"class_name":"EventLog"},
|
||||||
|
"event_logs:sources:created": {"key":"sources:created","ct":1,"first_at":1766987075389,"last_at":1766987075389,"class_name":"EventLog","event_sources":{"obsidian:vault.create":1}},
|
||||||
|
"event_logs:event_log:first": {"key":"event_log:first","ct":14,"first_at":1766986874718,"last_at":1766987077711,"class_name":"EventLog"},
|
||||||
|
"event_logs:sources:created": {"key":"sources:created","ct":2,"first_at":1766987075389,"last_at":1766987077702,"class_name":"EventLog","event_sources":{"obsidian:vault.create":2}},
|
||||||
|
"event_logs:sources:modified": {"key":"sources:modified","ct":1,"first_at":1766987077711,"last_at":1766987077711,"class_name":"EventLog","event_sources":{"obsidian:vault.modify":1}},
|
||||||
|
"event_logs:sources:modified": {"key":"sources:modified","ct":2,"first_at":1766987077711,"last_at":1766987081391,"class_name":"EventLog","event_sources":{"obsidian:vault.modify":2}},
|
||||||
|
"event_logs:event_log:first": {"key":"event_log:first","ct":15,"first_at":1766986874718,"last_at":1766987089766,"class_name":"EventLog"},
|
||||||
|
"event_logs:sources:deleted": {"key":"sources:deleted","ct":1,"first_at":1766987089766,"last_at":1766987089766,"class_name":"EventLog","event_sources":{"obsidian:vault.delete":1}},
|
||||||
|
"event_logs:sources:deleted": {"key":"sources:deleted","ct":2,"first_at":1766987089766,"last_at":1766987094937,"class_name":"EventLog","event_sources":{"obsidian:vault.delete":2}},
|
||||||
|
"event_logs:event_log:first": {"key":"event_log:first","ct":16,"first_at":1766986874718,"last_at":1766987105710,"class_name":"EventLog"},
|
||||||
|
"event_logs:sources:created": {"key":"sources:created","ct":3,"first_at":1766987075389,"last_at":1766987105674,"class_name":"EventLog","event_sources":{"obsidian:vault.create":3}},
|
||||||
|
"event_logs:sources:opened": {"key":"sources:opened","ct":1,"first_at":1766987105710,"last_at":1766987105710,"class_name":"EventLog","event_sources":{"active-leaf-change":1}},
|
||||||
|
"event_logs:sources:modified": {"key":"sources:modified","ct":3,"first_at":1766987077711,"last_at":1766987133412,"class_name":"EventLog","event_sources":{"obsidian:vault.modify":2,"obsidian:workspace.editor-change":1}},
|
||||||
|
"event_logs:sources:modified": {"key":"sources:modified","ct":7,"first_at":1766987077711,"last_at":1766987135416,"class_name":"EventLog","event_sources":{"obsidian:vault.modify":3,"obsidian:workspace.editor-change":4}},
|
||||||
|
"event_logs:sources:modified": {"key":"sources:modified","ct":16,"first_at":1766987077711,"last_at":1766987140295,"class_name":"EventLog","event_sources":{"obsidian:vault.modify":4,"obsidian:workspace.editor-change":12}},
|
||||||
|
"event_logs:sources:imported": {"key":"sources:imported","ct":449,"first_at":1766986877786,"last_at":1766987142184,"class_name":"EventLog"},
|
||||||
|
"event_logs:sources:modified": {"key":"sources:modified","ct":24,"first_at":1766987077711,"last_at":1766987142109,"class_name":"EventLog","event_sources":{"obsidian:vault.modify":5,"obsidian:workspace.editor-change":19}},
|
||||||
|
"event_logs:sources:modified": {"key":"sources:modified","ct":34,"first_at":1766987077711,"last_at":1766987145892,"class_name":"EventLog","event_sources":{"obsidian:vault.modify":7,"obsidian:workspace.editor-change":27}},
|
||||||
|
"event_logs:sources:modified": {"key":"sources:modified","ct":46,"first_at":1766987077711,"last_at":1766987150337,"class_name":"EventLog","event_sources":{"obsidian:vault.modify":9,"obsidian:workspace.editor-change":37}},
|
||||||
|
"event_logs:sources:modified": {"key":"sources:modified","ct":56,"first_at":1766987077711,"last_at":1766987152862,"class_name":"EventLog","event_sources":{"obsidian:vault.modify":10,"obsidian:workspace.editor-change":46}},
|
||||||
|
"event_logs:sources:modified": {"key":"sources:modified","ct":57,"first_at":1766987077711,"last_at":1766987154420,"class_name":"EventLog","event_sources":{"obsidian:vault.modify":11,"obsidian:workspace.editor-change":46}},
|
||||||
|
"event_logs:sources:imported": {"key":"sources:imported","ct":450,"first_at":1766986877786,"last_at":1766987156523,"class_name":"EventLog"},
|
||||||
|
"event_logs:sources:modified": {"key":"sources:modified","ct":58,"first_at":1766987077711,"last_at":1766987407748,"class_name":"EventLog","event_sources":{"obsidian:vault.modify":11,"obsidian:workspace.editor-change":47}},
|
||||||
|
"event_logs:sources:modified": {"key":"sources:modified","ct":59,"first_at":1766987077711,"last_at":1766987408636,"class_name":"EventLog","event_sources":{"obsidian:vault.modify":11,"obsidian:workspace.editor-change":48}},
|
||||||
|
"event_logs:sources:modified": {"key":"sources:modified","ct":60,"first_at":1766987077711,"last_at":1766987409752,"class_name":"EventLog","event_sources":{"obsidian:vault.modify":12,"obsidian:workspace.editor-change":48}},
|
||||||
|
"event_logs:sources:modified": {"key":"sources:modified","ct":61,"first_at":1766987077711,"last_at":1766987414884,"class_name":"EventLog","event_sources":{"obsidian:vault.modify":12,"obsidian:workspace.editor-change":49}},
|
||||||
|
"event_logs:sources:modified": {"key":"sources:modified","ct":62,"first_at":1766987077711,"last_at":1766987416887,"class_name":"EventLog","event_sources":{"obsidian:vault.modify":13,"obsidian:workspace.editor-change":49}},
|
||||||
|
"event_logs:sources:imported": {"key":"sources:imported","ct":451,"first_at":1766986877786,"last_at":1766987420759,"class_name":"EventLog"},
|
||||||
|
"event_logs:sources:modified": {"key":"sources:modified","ct":95,"first_at":1766987077711,"last_at":1766987427062,"class_name":"EventLog","event_sources":{"obsidian:vault.modify":14,"obsidian:workspace.editor-change":81}},
|
||||||
|
"event_logs:sources:modified": {"key":"sources:modified","ct":96,"first_at":1766987077711,"last_at":1766987428427,"class_name":"EventLog","event_sources":{"obsidian:vault.modify":15,"obsidian:workspace.editor-change":81}},
|
||||||
|
"event_logs:sources:imported": {"key":"sources:imported","ct":452,"first_at":1766986877786,"last_at":1766987437279,"class_name":"EventLog"},
|
||||||
+401
@@ -0,0 +1,401 @@
|
|||||||
|
|
||||||
|
|
||||||
|
# Soft Serve 安装指南(Docker Compose + Traefik TCP + CNAME)
|
||||||
|
|
||||||
|
## 1. 目标与最终形态
|
||||||
|
|
||||||
|
- 域名:`repo.windy.me`
|
||||||
|
|
||||||
|
- DNS:`repo.windy.me` **CNAME → `us2.wsvc.info`**
|
||||||
|
|
||||||
|
- 部署主机:`us2.wsvc.info` 对应的 VPS(本文称 “us2”)
|
||||||
|
|
||||||
|
- Soft Serve 镜像:`ghcr.io/charmbracelet/soft-serve:latest`
|
||||||
|
|
||||||
|
- 数据持久化:宿主机 `./data` → 容器 `/var/lib/soft-serve`
|
||||||
|
|
||||||
|
- 访问方式:SSH(Soft Serve SSH 服务端口为容器内 `23231`)
|
||||||
|
|
||||||
|
- 暴露方式(推荐):Traefik TCP entrypoint `ssh` 监听宿主机 `2222`,转发到容器 `23231`
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 前置条件清单
|
||||||
|
|
||||||
|
### 2.1 DNS(CNAME)
|
||||||
|
|
||||||
|
你已设置:
|
||||||
|
|
||||||
|
- `repo.windy.me` CNAME → `us2.wsvc.info`
|
||||||
|
|
||||||
|
|
||||||
|
关键含义:
|
||||||
|
|
||||||
|
- 用户访问 `repo.windy.me` 时,最终会解析到 **us2 的公网 IP**
|
||||||
|
|
||||||
|
- 只要 us2 上对外开放 SSH 入口端口(示例:2222),访问就成立
|
||||||
|
|
||||||
|
|
||||||
|
建议验证(任意机器):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
dig +short repo.windy.me CNAME
|
||||||
|
dig +short repo.windy.me A
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2.2 网络与防火墙
|
||||||
|
|
||||||
|
在 us2 上确保对外放行你用于 Soft Serve SSH 的端口(示例 2222):
|
||||||
|
|
||||||
|
- 入站允许:TCP 2222
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2.3 Traefik 已存在并使用外部网络
|
||||||
|
|
||||||
|
你当前 compose 使用:
|
||||||
|
|
||||||
|
- external network:`vw-net`
|
||||||
|
|
||||||
|
|
||||||
|
确保 Traefik 容器也在同一个 `vw-net` 网络内。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 准备目录与配置文件
|
||||||
|
|
||||||
|
在 us2 上:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir -p /opt/soft-serve
|
||||||
|
cd /opt/soft-serve
|
||||||
|
mkdir -p data
|
||||||
|
```
|
||||||
|
|
||||||
|
最终结构:
|
||||||
|
|
||||||
|
```
|
||||||
|
/opt/soft-serve/
|
||||||
|
compose.yml
|
||||||
|
.env
|
||||||
|
data/
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. 准备初始化管理员公钥(必须)
|
||||||
|
|
||||||
|
Soft Serve 首次启动会根据环境变量写入初始管理员 key。你已经验证的公钥写法如下(单行):
|
||||||
|
|
||||||
|
`.env`:
|
||||||
|
|
||||||
|
```env
|
||||||
|
SOFT_SERVE_INITIAL_ADMIN_KEYS=ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIE9irsGu03p+1xrwIfzrzjGZCcExJ/XFEgkqsgfEN70j windy@windy-mbp
|
||||||
|
```
|
||||||
|
|
||||||
|
注意事项:
|
||||||
|
|
||||||
|
- 必须是 **完整公钥的一整行**
|
||||||
|
|
||||||
|
- 只在 **数据目录首次初始化(空目录)** 时生效
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Docker Compose(推荐:Traefik TCP 暴露 SSH)
|
||||||
|
|
||||||
|
`compose.yml`(与你当前成功的结构一致,并保留注释):
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
soft-serve:
|
||||||
|
image: ghcr.io/charmbracelet/soft-serve:latest
|
||||||
|
container_name: soft-serve
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
environment:
|
||||||
|
SOFT_SERVE_DATA_PATH: /var/lib/soft-serve
|
||||||
|
SOFT_SERVE_INITIAL_ADMIN: windy
|
||||||
|
SOFT_SERVE_INITIAL_ADMIN_KEYS: ${SOFT_SERVE_INITIAL_ADMIN_KEYS}
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
- ./data:/var/lib/soft-serve
|
||||||
|
|
||||||
|
# 方案B:直连端口映射(不走 Traefik)
|
||||||
|
# ports:
|
||||||
|
# - "2222:23231"
|
||||||
|
|
||||||
|
networks:
|
||||||
|
- traefik
|
||||||
|
|
||||||
|
labels:
|
||||||
|
- traefik.enable=true
|
||||||
|
|
||||||
|
# SSH over TCP via Traefik (entryPoint ssh -> container port 23231)
|
||||||
|
- traefik.tcp.routers.softserve-ssh.entrypoints=ssh
|
||||||
|
- traefik.tcp.routers.softserve-ssh.rule=HostSNI(`*`)
|
||||||
|
- traefik.tcp.routers.softserve-ssh.tls=false
|
||||||
|
- traefik.tcp.services.softserve-ssh.loadbalancer.server.port=23231
|
||||||
|
|
||||||
|
networks:
|
||||||
|
traefik:
|
||||||
|
external: true
|
||||||
|
name: vw-net
|
||||||
|
```
|
||||||
|
|
||||||
|
### 关于 “SSH 不能走 Traefik 代理域名分流”的结论
|
||||||
|
|
||||||
|
- SSH 不是 HTTP;Traefik 在这里是 **TCP 转发**
|
||||||
|
|
||||||
|
- 不要使用 `HostSNI(repo.windy.me)` 之类的规则来“按域名”分流 SSH(会引发 TLS/HostSNI 相关报错)
|
||||||
|
|
||||||
|
- 最稳妥的做法就是:
|
||||||
|
|
||||||
|
- `tls=false`
|
||||||
|
|
||||||
|
- `HostSNI('*')`
|
||||||
|
|
||||||
|
- 依赖端口入口(2222)
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Traefik 静态配置要求(必须有 entrypoint)
|
||||||
|
|
||||||
|
你必须在 Traefik 的静态配置中定义 `ssh` entrypoint,并监听对外端口(示例:2222)。
|
||||||
|
|
||||||
|
示例(只示意关键段):
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
entryPoints:
|
||||||
|
ssh:
|
||||||
|
address: ":2222"
|
||||||
|
```
|
||||||
|
|
||||||
|
如果缺失,会出现典型错误:
|
||||||
|
|
||||||
|
- `EntryPoint doesn't exist entryPointName=ssh`
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. 首次启动与“只初始化一次”的规则
|
||||||
|
|
||||||
|
### 7.1 首次启动
|
||||||
|
|
||||||
|
在 `/opt/soft-serve`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose up -d
|
||||||
|
docker compose ps
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7.2 初始化只发生一次(关键规则)
|
||||||
|
|
||||||
|
如需重新初始化(比如 `.env` 修改后不生效),必须清空数据目录:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose down
|
||||||
|
rm -rf ./data
|
||||||
|
mkdir -p ./data
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. 客户端连接与“user not found”修正方法
|
||||||
|
|
||||||
|
### 8.1 强制使用指定 key(排错与首次推荐)
|
||||||
|
|
||||||
|
你最终验证成功的关键点是:**固定 key + IdentitiesOnly**。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ssh -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519 -p 2222 repo.windy.me info
|
||||||
|
```
|
||||||
|
|
||||||
|
若成功会输出类似:
|
||||||
|
|
||||||
|
```
|
||||||
|
Username: admin (或 windy)
|
||||||
|
Admin: true
|
||||||
|
Public keys: ...
|
||||||
|
```
|
||||||
|
|
||||||
|
### 8.2 把默认用户名从 `admin` 改成 `windy`
|
||||||
|
|
||||||
|
你已成功的改名命令(注意同样要固定 key):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ssh -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519 -p 2222 repo.windy.me set-username windy
|
||||||
|
ssh -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519 -p 2222 repo.windy.me info
|
||||||
|
```
|
||||||
|
|
||||||
|
**解释:**“user not found” 的真实根因通常不是 Soft Serve 没用户,而是 SSH 客户端未固定 key 时选用了另一把 key,导致 Soft Serve 无法把该连接映射到已存在的用户。
|
||||||
|
|
||||||
|
### 8.3 永久固化:写 `~/.ssh/config`
|
||||||
|
|
||||||
|
在本机写入:
|
||||||
|
|
||||||
|
```sshconfig
|
||||||
|
Host repo.windy.me
|
||||||
|
HostName repo.windy.me
|
||||||
|
Port 2222
|
||||||
|
User git
|
||||||
|
IdentityFile ~/.ssh/id_ed25519
|
||||||
|
IdentitiesOnly yes
|
||||||
|
```
|
||||||
|
|
||||||
|
之后即可:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ssh repo.windy.me info
|
||||||
|
ssh repo.windy.me repo list
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. 创建仓库与 Git clone/push
|
||||||
|
|
||||||
|
### 9.1 创建仓库
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ssh repo.windy.me repo create test
|
||||||
|
ssh repo.windy.me repo list
|
||||||
|
```
|
||||||
|
|
||||||
|
### 9.2 Clone(推荐写法)
|
||||||
|
|
||||||
|
写法 A(最清晰):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone ssh://repo.windy.me:2222/test.git
|
||||||
|
```
|
||||||
|
|
||||||
|
写法 B(scp 风格,依赖 ssh config 的 Port):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone repo.windy.me:test.git
|
||||||
|
```
|
||||||
|
|
||||||
|
### 9.3 Push 验证
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd test
|
||||||
|
echo "# test" > README.md
|
||||||
|
git add .
|
||||||
|
git commit -m "init"
|
||||||
|
git push
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10. 常见故障排查(快速定位)
|
||||||
|
|
||||||
|
### 10.1 连接到错误端口
|
||||||
|
|
||||||
|
现象:你以为是 23231,但实际对外是 2222(由 Traefik entrypoint 决定)。
|
||||||
|
|
||||||
|
验证(在 us2 上):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ss -lntp | grep :2222
|
||||||
|
```
|
||||||
|
|
||||||
|
应看到 Traefik 监听 2222。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 10.2 `EntryPoint doesn't exist entryPointName=ssh`
|
||||||
|
|
||||||
|
原因:Traefik 静态配置未定义 `entryPoints.ssh`。
|
||||||
|
|
||||||
|
修复:给 Traefik 增加:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
entryPoints:
|
||||||
|
ssh:
|
||||||
|
address: ":2222"
|
||||||
|
```
|
||||||
|
|
||||||
|
并重启 Traefik。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 10.3 `Error: user not found`
|
||||||
|
|
||||||
|
高概率原因:SSH 客户端用了“另一把 key”。
|
||||||
|
|
||||||
|
修复(强制固定 key):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ssh -vvv -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519 -p 2222 repo.windy.me info
|
||||||
|
```
|
||||||
|
|
||||||
|
观察日志中是否出现:
|
||||||
|
|
||||||
|
- `Offering public key: ... id_ed25519`
|
||||||
|
|
||||||
|
- `Server accepts key: ... id_ed25519`
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 11. 备份与恢复(生产建议)
|
||||||
|
|
||||||
|
### 11.1 需要备份的内容
|
||||||
|
|
||||||
|
Soft Serve 核心数据都在宿主机 `./data`(映射自 `/var/lib/soft-serve`):
|
||||||
|
|
||||||
|
- `soft-serve.db`(用户/设置)
|
||||||
|
|
||||||
|
- `repos/`(仓库数据,如存在)
|
||||||
|
|
||||||
|
- `ssh/`(host keys 等)
|
||||||
|
|
||||||
|
|
||||||
|
### 11.2 最简单备份命令
|
||||||
|
|
||||||
|
在 us2 上:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /opt/soft-serve
|
||||||
|
tar -czf soft-serve-backup-$(date +%F).tar.gz ./data
|
||||||
|
```
|
||||||
|
|
||||||
|
恢复流程:
|
||||||
|
|
||||||
|
1. `docker compose down`
|
||||||
|
|
||||||
|
2. 解压覆盖 `./data`
|
||||||
|
|
||||||
|
3. `docker compose up -d`
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 12. 推荐的“最终检查清单”
|
||||||
|
|
||||||
|
- `repo.windy.me` CNAME 指向 `us2.wsvc.info`,并能解析到 us2 IP
|
||||||
|
|
||||||
|
- us2 对外开放 TCP 2222
|
||||||
|
|
||||||
|
- Traefik 静态配置存在 `entryPoints.ssh=:2222`
|
||||||
|
|
||||||
|
- Soft Serve 数据目录持久化:`./data:/var/lib/soft-serve`
|
||||||
|
|
||||||
|
- 客户端 `~/.ssh/config` 固定 `IdentityFile` + `IdentitiesOnly yes`
|
||||||
|
|
||||||
|
- `ssh repo.windy.me info` 输出 `Username: windy` 且 `Admin: true`
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
如果你希望我把这份指南进一步“落地化”,我可以再给你两个附录(可选):
|
||||||
|
|
||||||
|
1. **一份生产级 compose**(healthcheck、日志限制、只读 filesystem、资源限制)
|
||||||
|
|
||||||
|
2. **一份 Traefik 静态配置片段**(与你当前 Traefik 容器的真实配置方式对齐:file provider / command args / labels)
|
||||||
Reference in New Issue
Block a user