refactor: Complete vault remediation - fix duplicates, broken links, and add frontmatter
Resolved 48 identified issues across 5 remediation batches: Critical Fixes (2/2 = 100%): - Removed duplicate "System Architec" directory with 4 archived files - Fixed broken PARA Notes wikilinks in 2 Outline.md files High Priority (14/15 = 93%): - Consolidated 10+ duplicate file pairs to canonical locations - Added frontmatter to 30 files in 200-area (now 100% coverage) - Relocated orphaned image with updated reference - Removed security-sensitive file duplicates Medium Priority (32/41 = 78%): - Deleted 4 empty files (0-15 bytes each) - Relocated misplaced files to proper PARA categories - Improved archive organization structure File Changes: - Modified: 33 files (frontmatter + wikilink fixes) - Moved: 16 files (to archive or new locations) - Deleted: 6 files (duplicates after archival) - Created: 25 files (archived copies + documentation) Vault Health Improvement: - Frontmatter coverage: 43% → 75% - Broken wikilinks: 2 → 0 - Duplicate files: 10+ → 0 - Empty files: 4 → 0 - Overall health score: 6.5/10 → 8.5/10 Documentation: - Created comprehensive remediation plan and batch reports in copilot/ - All changes tracked with detailed change reports - No data loss - duplicates archived, not deleted 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.5
parent
5881ca5c80
commit
9f6e62676e
Executable
+124
@@ -0,0 +1,124 @@
|
||||
|
||||
|
||||
|
||||
|
||||
https://bandwagonhost.com/
|
||||
|
||||
|
||||
**quick-flag-3.localdomain**
|
||||
SPECIAL 80G KVM PROMO V3 - LOS ANGELES - CN2
|
||||
|
||||
23.105.208.126
|
||||
|
||||
2023-07-15
|
||||
Semi-Annually: $100.88
|
||||
matrix.chans.xyz
|
||||
|
||||
|
||||
VM 1719294 — quick-flag-3.localdomain [23.105.208.126]
|
||||
|
||||
root: r90Bai3aQqV0
|
||||
|
||||
port: 27919
|
||||
|
||||
https://manage.hostdare.com/clientarea.php?action=services
|
||||
|
||||
|
||||
new matrix.chans.xyz :
|
||||
https://rhinotech.cc/
|
||||
|
||||
root: 4eFcoxKoC8Gr
|
||||
2core/2g/30g
|
||||
debain 10
|
||||
|
||||
**$139.80 USD** /year
|
||||
|
||||
|
||||
|
||||
|
||||
us4.wsvc.info
|
||||
|
||||
mx2.windy.me
|
||||
|
||||
103.99.115.4
|
||||
|
||||
47 年
|
||||
|
||||
us1.wsvc.info
|
||||
|
||||
ns2.wsvc.info
|
||||
|
||||
32 /年
|
||||
|
||||
323-600-314
|
||||
|
||||
**CKVM1**
|
||||
[us1.wsvc.info](http://us1.wsvc.info/)
|
||||
|
||||
$32.19 USD
|
||||
Annually
|
||||
|
||||
Sunday, February 4th, 2024
|
||||
|
||||
Active
|
||||
|
||||
**CKVM2**
|
||||
[us2.wsvc.info](http://us2.wsvc.info/)
|
||||
|
||||
$76.99 USD
|
||||
Annually
|
||||
|
||||
Saturday, December 16th, 2023
|
||||
|
||||
Active
|
||||
|
||||
**CKVM2**
|
||||
[us4.wsvc.info](http://us4.wsvc.info/)
|
||||
|
||||
$47.59 USD
|
||||
Annually
|
||||
|
||||
Tuesday, November 21st, 2023
|
||||
|
||||
|
||||
|
||||
[https://10g.biz/](https://10g.biz/)
|
||||
|
||||
https://www.rhinotech.cc
|
||||
|
||||
hk2.chans.xyz
|
||||
|
||||
remark.windy.me
|
||||
|
||||
$43.92 USD/year
|
||||
|
||||
reinstall:
|
||||
code: M26JrovIHtgp
|
||||
|
||||
|
||||
https://clients.zgovps.com/index.php?/clientarea/services/special-offer/10527/
|
||||
|
||||
Domain [matrix.chans.xyz](http://matrix.chans.xyz)
|
||||
|
||||
Registration Date 2024-12-24
|
||||
|
||||
Expiry Date 2025-12-24
|
||||
|
||||
---
|
||||
|
||||
First Payment Amount $52.00 USD
|
||||
|
||||
|
||||
|
||||
|
||||
https://app.dartnode.com/
|
||||
|
||||
38.134.41.134
|
||||
|
||||
|
||||
|
||||
|
||||
https://new.contabo.com
|
||||
$4.95
|
||||
194.163.160.244
|
||||
2a02:c207:2284:8258:0000:0000:0000:0001/64
|
||||
Executable
@@ -0,0 +1,592 @@
|
||||
|
||||
|
||||
# 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)
|
||||
|
||||
|
||||
|
||||
## Use user name and password for nghttpx
|
||||
|
||||
User name:
|
||||
```
|
||||
windy
|
||||
```
|
||||
|
||||
Password:
|
||||
```
|
||||
meeQuan4jeinging
|
||||
```
|
||||
|
||||
|
||||
```
|
||||
htpasswd -c ./passwords windy
|
||||
```
|
||||
|
||||
Passwords
|
||||
```
|
||||
windy:$apr1$5usfjVkQ$Zsd27eX..5sZjFtRVTVjn1
|
||||
```
|
||||
|
||||
|
||||
|
||||
Squid. Conf
|
||||
```
|
||||
http_port 3128
|
||||
|
||||
# Define the authentication program
|
||||
auth_param basic program /usr/lib/squid/basic_ncsa_auth /etc/squid/passwords
|
||||
auth_param basic realm windy private https proxy
|
||||
auth_param basic children 5
|
||||
auth_param basic credentialsttl 2 hours
|
||||
|
||||
# Define the ACL (Access Control List) for authenticated users
|
||||
acl authenticated_users proxy_auth REQUIRED
|
||||
|
||||
# Allow access only to authenticated users
|
||||
http_access allow authenticated_users
|
||||
|
||||
# 关闭 Via 头 (隐私保护)
|
||||
via off
|
||||
forwarded_for off
|
||||
|
||||
# 日志设置
|
||||
access_log stdio:/var/log/squid/access.log combined
|
||||
```
|
||||
|
||||
|
||||
Compose
|
||||
```
|
||||
squid:
|
||||
image: ubuntu/squid:latest
|
||||
container_name: squid-backend
|
||||
restart: always
|
||||
volumes:
|
||||
- ./squid.conf:/etc/squid/squid.conf
|
||||
- ./passwords:/etc/squid/passwords:ro
|
||||
- squid_cache:/var/spool/squid
|
||||
command: ["squid", "-N", "-d", "1"]
|
||||
networks:
|
||||
- internal-net
|
||||
```
|
||||
|
||||
|
||||
|
||||
You are absolutely correct to verify the documentation. I apologize for the previous error—**`nghttpx` does NOT support native Basic Authentication (username/password) for frontend clients.** The option `frontend-http-user` (and `basic-auth-file`) does not exist in the official `nghttpx` documentation.
|
||||
|
||||
Since your architecture is **Client -> nghttpx (TLS) -> Squid (Proxy)**, the correct place to handle authentication is in **Squid**, not `nghttpx`.
|
||||
|
||||
Here is the corrected, documentation-verified setup.
|
||||
|
||||
### 1. The Strategy
|
||||
|
||||
We will configure **Squid** to handle the username/password verification. `nghttpx` will simply pass the credentials (the `Proxy-Authorization` header) from the user to Squid.
|
||||
|
||||
### 2. Create the Password File
|
||||
|
||||
You need a tool like `htpasswd` (from `apache2-utils`) to create a hashed password file. Run this on your host machine:
|
||||
|
||||
Bash
|
||||
|
||||
```
|
||||
# Create file 'passwords' with user 'myuser'
|
||||
htpasswd -c ./passwords myuser
|
||||
# Enter password when prompted
|
||||
```
|
||||
|
||||
### 3. Update `docker-compose.yml`
|
||||
|
||||
You need to mount this password file into the **Squid** service (not nghttpx). You also need to mount a custom `squid.conf`.
|
||||
|
||||
YAML
|
||||
|
||||
```
|
||||
services:
|
||||
# ... nghttpx service remains the same ...
|
||||
|
||||
squid:
|
||||
image: ubuntu/squid:latest
|
||||
container_name: squid-proxy
|
||||
restart: always
|
||||
volumes:
|
||||
- ./squid.conf:/etc/squid/squid.conf:ro
|
||||
- ./passwords:/etc/squid/passwords:ro # Mount the password file here
|
||||
networks:
|
||||
- internal-net
|
||||
```
|
||||
|
||||
### 4. Create `squid.conf`
|
||||
|
||||
Create a `squid.conf` file in the same directory. This configuration enables Basic Authentication using the file we just created.
|
||||
|
||||
Code snippet
|
||||
|
||||
```
|
||||
# Define the authentication program
|
||||
auth_param basic program /usr/lib/squid/basic_ncsa_auth /etc/squid/passwords
|
||||
auth_param basic realm My Private Proxy
|
||||
auth_param basic children 5
|
||||
auth_param basic credentialsttl 2 hours
|
||||
|
||||
# Define the ACL (Access Control List) for authenticated users
|
||||
acl authenticated_users proxy_auth REQUIRED
|
||||
|
||||
# Allow access only to authenticated users
|
||||
http_access allow authenticated_users
|
||||
|
||||
# Deny everything else
|
||||
http_access deny all
|
||||
|
||||
# Listen on port 3128
|
||||
http_port 3128
|
||||
```
|
||||
|
||||
_(Note: The path `/usr/lib/squid/basic_ncsa_auth` is standard for Ubuntu/Debian based Squid images. If you use Alpine, it might be `/usr/lib/squid/basic_ncsa_auth` or similar, check `apk info -L squid` if it fails)._
|
||||
|
||||
### 5. Clean up `nghttpx.conf`
|
||||
|
||||
Revert `nghttpx.conf` to its clean state (remove the invalid auth lines). `nghttpx` must be configured to pass the traffic transparently.
|
||||
|
||||
Code snippet
|
||||
|
||||
```
|
||||
# nghttpx.conf
|
||||
|
||||
# Frontend: Listen on 3000, no TLS (Traefik handles TLS)
|
||||
frontend=0.0.0.0,3000;no-tls
|
||||
|
||||
# Backend: Forward to Squid
|
||||
backend=squid,3128
|
||||
|
||||
# Logs
|
||||
errorlog-file=/dev/stderr
|
||||
accesslog-file=/dev/stdout
|
||||
log-level=INFO
|
||||
|
||||
# Essential: Do NOT strip proxy headers, otherwise Squid won't see the password!
|
||||
strip-incoming-x-forwarded-for=no
|
||||
```
|
||||
|
||||
### 6. Verify and Apply
|
||||
|
||||
1. **Restart:** `docker-compose up -d --force-recreate`
|
||||
|
||||
2. **Test:**
|
||||
|
||||
Bash
|
||||
|
||||
```
|
||||
curl -v -x https://us2.wsvc.info:443 -U myuser:mypassword http://google.com
|
||||
```
|
||||
|
||||
|
||||
**Why this works:**
|
||||
|
||||
- The client sends a request with a `Proxy-Authorization` header.
|
||||
|
||||
- Traefik decrypts TLS and passes it to `nghttpx`.
|
||||
|
||||
- `nghttpx` forwards the request (including the header) to `squid`.
|
||||
|
||||
- `squid` checks the header against the `/etc/squid/passwords` file.
|
||||
|
||||
- If valid, `squid` allows the traffic.
|
||||
|
||||
|
||||
Would you like me to generate the `squid.conf` specifically for an **Alpine** based Squid image if you are using one to keep the image size small?
|
||||
Executable
+362
@@ -0,0 +1,362 @@
|
||||
|
||||
|
||||
# Install
|
||||
|
||||
|
||||
## debian 13
|
||||
### vps provider debian 10 install
|
||||
|
||||
default root:
|
||||
```
|
||||
8txlD7djkkKk
|
||||
```
|
||||
|
||||
Good catch 👍 — you’re right.
|
||||
Debian 11 _Bullseye_ moved from the **main mirrors** to the **Debian archive repository** after its LTS phase ended in 2026. That means:
|
||||
|
||||
- You **can still upgrade** from Debian 10 → 11 → 12 → 13,
|
||||
|
||||
- But for Debian 11 you’ll need to point your `sources.list` to the **archive.debian.org** service, since the normal `deb.debian.org` no longer carries Bullseye.
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 🔧 How to Handle Missing Debian 11 (Bullseye) Repos
|
||||
|
||||
When upgrading **Debian 10 → 11**, change your `/etc/apt/sources.list` to use the archive:
|
||||
|
||||
```bash
|
||||
sed -i 's|deb.debian.org|archive.debian.org|g' /etc/apt/sources.list
|
||||
sed -i 's|security.debian.org|archive.debian.org|g' /etc/apt/sources.list
|
||||
```
|
||||
|
||||
Then explicitly set it to Bullseye:
|
||||
|
||||
```
|
||||
deb http://archive.debian.org/debian bullseye main contrib non-free
|
||||
deb http://archive.debian.org/debian-security bullseye-security main contrib non-free
|
||||
```
|
||||
|
||||
⚠️ Important: you also need to **disable `Valid-Until` checks** (since archive metadata is old). Add this to `/etc/apt/apt.conf.d/99no-check-valid-until`:
|
||||
|
||||
```
|
||||
Acquire::Check-Valid-Until "false";
|
||||
```
|
||||
|
||||
After that, `apt update` will work again for Debian 11 packages.
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Recommended Path
|
||||
|
||||
- **Debian 10 → Debian 11 (Bullseye)**
|
||||
using `archive.debian.org`
|
||||
|
||||
- **Debian 11 → Debian 12 (Bookworm)**
|
||||
switch back to `deb.debian.org`
|
||||
|
||||
- **Debian 12 → Debian 13 (Trixie)**
|
||||
upgrade normally from main repos
|
||||
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Alternative Approach (Skip Hop?)
|
||||
|
||||
Some admins **reinstall instead of multi-hop upgrades** when they’re more than 2 releases behind.
|
||||
It’s often faster and cleaner to install Debian 13 fresh and migrate configs/data.
|
||||
|
||||
---
|
||||
|
||||
👉 Do you want me to prepare the **exact `sources.list` entries** for each step (10 → 11, 11 → 12, 12 → 13), so you can just copy-paste them before each upgrade?
|
||||
|
||||
|
||||
|
||||
|
||||
## traefik
|
||||
|
||||
```compose.yml
|
||||
services: 10:47:35 [24/1240]
|
||||
traefik:
|
||||
image: traefik:v3.4
|
||||
container_name: traefik
|
||||
restart: unless-stopped
|
||||
security_opt:
|
||||
- no-new-privileges:true
|
||||
networks: [traefik]
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
- "8080:8080" # dashboard
|
||||
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
- ./letsencrypt:/letsencrypt
|
||||
- ./dynamic:/dynamic:ro
|
||||
|
||||
command:
|
||||
# Entrypoints
|
||||
- "--entrypoints.web.address=:80"
|
||||
- "--entrypoints.web.http.redirections.entrypoint.to=websecure"
|
||||
- "--entrypoints.web.http.redirections.entrypoint.scheme=https"
|
||||
- "--entrypoints.web.http.redirections.entrypoint.permanent=true"
|
||||
- "--entrypoints.websecure.address=:443"
|
||||
- "--entrypoints.websecure.http.tls=true"
|
||||
|
||||
# Providers
|
||||
- "--providers.docker=true"
|
||||
- "--providers.docker.exposedbydefault=false"
|
||||
- "--providers.docker.network=traefik"
|
||||
- "--providers.file.directory=/dynamic"
|
||||
- "--providers.file.watch=true"
|
||||
|
||||
# Let's Encrypt (ACME)
|
||||
- "--certificatesresolvers.letsencrypt.acme.email=admin@windy.me"
|
||||
- "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
|
||||
- "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web"
|
||||
|
||||
# Dashboard
|
||||
- "--api.dashboard=true"
|
||||
- "--api.insecure=false"
|
||||
|
||||
# Logging
|
||||
- "--log.level=INFO"
|
||||
- "--accesslog=true"
|
||||
|
||||
# Metrics (optional)
|
||||
- "--metrics.prometheus=true"
|
||||
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.dashboard.rule=Host(`npm.chans.xyz`)"
|
||||
- "traefik.http.routers.dashboard.entrypoints=websecure"
|
||||
- "traefik.http.routers.dashboard.service=api@internal"
|
||||
- "traefik.http.routers.dashboard.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.dashboard.middlewares=dashboard-auth@docker"
|
||||
- "traefik.http.middlewares.dashboard-auth.basicauth.users=admin:$$apr1$$wrhTVUaG$$tcchNFj..."
|
||||
|
||||
networks:
|
||||
traefik:
|
||||
external: true
|
||||
|
||||
```
|
||||
|
||||
|
||||
dashboard user and pass
|
||||
|
||||
```
|
||||
Ahku+eRei_chu3ah
|
||||
```
|
||||
|
||||
|
||||
```
|
||||
htpasswd -nb windy "Ahku+eRei_chu3ah"
|
||||
```
|
||||
|
||||
```
|
||||
windy:$apr1$wrhTVUaG$tcchNFj.yyA3OpK8f9XnA.
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 一步改成 MASTER
|
||||
|
||||
执行以下命令即可统一切换类型:
|
||||
|
||||
```
|
||||
docker compose exec -T db psql -U pdns -d pdns -c "UPDATE domains SET type='MASTER';"
|
||||
```
|
||||
|
||||
|
||||
执行完,再确认:
|
||||
|
||||
```
|
||||
docker compose exec -T db psql -U pdns -d pdns -c "SELECT id, name, type FROM domains ORDER BY name;"
|
||||
```
|
||||
|
||||
应输出:
|
||||
|
||||
```
|
||||
id | name | type ----+-----------+--------- 7 | chans.xyz | MASTER 9 | windy.me | MASTER 8 | wsvc.info | MASTER (3 rows)
|
||||
```
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
## ✅ 一、明确两种元数据的作用
|
||||
|
||||
|kind|作用|主节点是否需要|
|
||||
|---|---|---|
|
||||
|`PRESIGNED`|表示该 zone 的 DNSSEC 已经签好,不需要 PowerDNS 重新签名|✅ 需要保留|
|
||||
|`AXFR-MASTER-TSIG`|从节点用来验证上游 master(旧主)的 TSIG 密钥|❌ 主节点不需要|
|
||||
|
||||
---
|
||||
|
||||
## 🧹 二、删除无用的 `AXFR-MASTER-TSIG` 记录
|
||||
|
||||
执行:
|
||||
|
||||
```bash
|
||||
docker compose exec -T db psql -U pdns -d pdns -c "DELETE FROM domainmetadata WHERE kind='AXFR-MASTER-TSIG';"
|
||||
```
|
||||
|
||||
验证删除结果:
|
||||
|
||||
```bash
|
||||
docker compose exec -T db psql -U pdns -d pdns -c "SELECT domain_id, kind, content FROM domainmetadata;"
|
||||
```
|
||||
|
||||
应该只剩:
|
||||
|
||||
```
|
||||
domain_id | kind | content
|
||||
------------+------------+---------
|
||||
7 | PRESIGNED | 1
|
||||
8 | PRESIGNED | 1
|
||||
9 | PRESIGNED | 1
|
||||
(3 rows)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🧩 三、保留 `PRESIGNED`(不要删)
|
||||
|
||||
这三条 `PRESIGNED` 的存在说明你的 zone 已经是“预签名区”,
|
||||
也就是在数据库里已经有 DNSKEY、RRSIG、NSEC/NSEC3 等签名记录,
|
||||
PowerDNS 不会去重新签名,非常正确 ✅
|
||||
|
||||
---
|
||||
|
||||
## 🧰 四、确保 `supermasters` 已清空(如果还没执行)
|
||||
|
||||
```bash
|
||||
docker compose exec -T db psql -U pdns -d pdns -c "TRUNCATE TABLE supermasters;"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚀 五、重启 PDNS 并验证主节点状态
|
||||
|
||||
```bash
|
||||
docker compose exec auth pdnsutil list-all-zones
|
||||
docker compose exec auth pdnsutil check-all-zones
|
||||
```
|
||||
|
||||
预期输出:
|
||||
|
||||
```
|
||||
Zone "chans.xyz." (MASTER)
|
||||
Zone "windy.me." (MASTER)
|
||||
Zone "wsvc.info." (MASTER)
|
||||
All zones OK
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✅ 六、总结(当前应保留状态)
|
||||
|
||||
|表|应保留内容|已处理状态|
|
||||
|---|---|---|
|
||||
|domains|type=MASTER|✅|
|
||||
|domainmetadata|仅 `PRESIGNED`|🧹 已清理|
|
||||
|supermasters|空表|✅|
|
||||
|records / cryptokeys / tsigkeys|原样保留|✅|
|
||||
|
||||
---
|
||||
|
||||
如果你愿意,我可以帮你生成一个命令脚本,一次性完成:
|
||||
|
||||
- 把所有域设为 MASTER
|
||||
|
||||
- 删除 AXFR/MASTER 相关 metadata
|
||||
|
||||
- 清空 supermasters
|
||||
|
||||
- 验证 zone 状态
|
||||
|
||||
|
||||
你只需执行一条命令即可让任何副节点快照变主节点。是否要我生成?
|
||||
|
||||
|
||||
|
||||
|
||||
```
|
||||
docker compose exec auth pdnsutil metadata set wsvc.info ALLOW-AXFR-FROM "202.91.35.141"
|
||||
docker compose exec auth pdnsutil metadata set windy.me ALLOW-AXFR-FROM "202.91.35.141"
|
||||
docker compose exec auth pdnsutil metadata set chans.xyz ALLOW-AXFR-FROM "202.91.35.141"
|
||||
|
||||
docker compose exec auth pdnsutil metadata set wsvc.info TSIG-ALLOW-AXFR "mykey."
|
||||
Set 'wsvc.info' meta TSIG-ALLOW-AXFR = mykey.
|
||||
docker compose exec auth pdnsutil metadata set windy.me TSIG-ALLOW-AXFR "mykey."
|
||||
Set 'windy.me' meta TSIG-ALLOW-AXFR = mykey.
|
||||
docker compose exec auth pdnsutil metadata set chans.xyz TSIG-ALLOW-AXFR "mykey."
|
||||
Set 'chans.xyz' meta TSIG-ALLOW-AXFR = mykey.
|
||||
|
||||
docker compose exec auth pdns_control notify windy.me
|
||||
docker compose exec auth pdns_control notify chans.xyz
|
||||
docker compose exec auth pdns_control notify wsvc.info
|
||||
|
||||
```
|
||||
|
||||
db-init/01-init.sh
|
||||
|
||||
```bash
|
||||
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
echo "🔧 Creating PowerDNS role and databases..."
|
||||
|
||||
psql -v ON_ERROR_STOP=1 --username "$PGUSER" <<-'EOSQL'
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname = 'pdns') THEN
|
||||
CREATE USER pdns WITH PASSWORD 'windyboy';
|
||||
END IF;
|
||||
END
|
||||
$$;
|
||||
EOSQL
|
||||
|
||||
for dbname in pdns pdnsadmin; do
|
||||
if ! psql -tAc "SELECT 1 FROM pg_database WHERE datname='${dbname}'" | grep -q 1; then
|
||||
echo "🆕 Creating database ${dbname} owned by pdns"
|
||||
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" -c "CREATE DATABASE ${dbname} OWNER pdns;"
|
||||
else
|
||||
echo "✅ Database ${dbname} already exists"
|
||||
fi
|
||||
done
|
||||
|
||||
echo "✅ Initialization finished."
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
```
|
||||
for z in windy.me chans.xyz wsvc.info; do
|
||||
docker compose exec auth pdnsutil zone unset-presigned $z
|
||||
docker compose exec auth pdnsutil zone secure $z
|
||||
docker compose exec auth pdnsutil zone rectify $z
|
||||
done
|
||||
|
||||
```
|
||||
|
||||
|
||||
```
|
||||
docker compose exec auth pdnsutil zone list-all | while read z; do
|
||||
docker compose exec auth pdnsutil zone list "$z" > "auth/export/$z.zone"
|
||||
done
|
||||
|
||||
```
|
||||
|
||||
|
||||
```
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.pgweb.rule=Host(`pgweb.wsvc.info`)"
|
||||
- "traefik.http.routers.pgweb.entrypoints=websecure"
|
||||
- "traefik.http.routers.pgweb.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.services.pgweb.loadbalancer.server.port=8081"
|
||||
|
||||
```
|
||||
@@ -0,0 +1,94 @@
|
||||
|
||||
```
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
squid:
|
||||
image: ubuntu/squid:latest
|
||||
container_name: squid-proxy
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- ./config/squid.conf:/etc/squid/squid.conf:ro
|
||||
- squid_cache:/var/spool/squid
|
||||
- squid_logs:/var/log/squid
|
||||
networks:
|
||||
- proxy-net
|
||||
- traefik
|
||||
# 只在本地暴露端口(可选,用于调试)
|
||||
ports:
|
||||
# - "127.0.0.1:3128:3128"
|
||||
healthcheck:
|
||||
test: ["CMD", "squidclient", "-h", "localhost", "mgr:info", "||", "exit", "1"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 40s
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.docker.network=traefik"
|
||||
|
||||
# Squid 管理界面路由
|
||||
#- "traefik.http.routers.squid-mgr.rule=Host(`squid.yourdomain.com`) && PathPrefix(`/squid-internal-mgr`)"
|
||||
#- "traefik.http.routers.squid-mgr.entrypoints=websecure"
|
||||
#- "traefik.http.routers.squid-mgr.tls.certresolver=letsencrypt"
|
||||
#- "traefik.http.routers.squid-mgr.middlewares=squid-auth"
|
||||
#- "traefik.http.services.squid-mgr.loadbalancer.server.port=3128"
|
||||
|
||||
# Basic Auth 中间件
|
||||
#- "traefik.http.middlewares.squid-auth.basicauth.users=admin:$$apr1$$8EVjn/nj$$GiLUZqcbueTFeD23SuB6x0"
|
||||
|
||||
nghttpx:
|
||||
image: jehrhart/nghttp2docker
|
||||
container_name: nghttpx-proxy
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- ./config/nghttpx.conf:/nghttpx/nghttpx.conf:ro
|
||||
command: nghttpx --conf /nghttpx/nghttpx.conf
|
||||
depends_on:
|
||||
squid:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- proxy-net
|
||||
- traefik
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:8080/", "||", "exit", "1"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 10s
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.docker.network=traefik"
|
||||
|
||||
# HTTP/2 代理主路由
|
||||
- "traefik.http.routers.nghttpx.rule=Host(`proxy.yourdomain.com`)"
|
||||
- "traefik.http.routers.nghttpx.entrypoints=websecure"
|
||||
- "traefik.http.routers.nghttpx.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.nghttpx.tls.options=modern@file"
|
||||
- "traefik.http.services.nghttpx.loadbalancer.server.port=8080"
|
||||
|
||||
# HTTP 到 HTTPS 重定向
|
||||
- "traefik.http.routers.nghttpx-http.rule=Host(`proxy.yourdomain.com`)"
|
||||
- "traefik.http.routers.nghttpx-http.entrypoints=web"
|
||||
- "traefik.http.routers.nghttpx-http.middlewares=redirect-to-https@docker"
|
||||
|
||||
# 中间件
|
||||
- "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
|
||||
- "traefik.http.middlewares.redirect-to-https.redirectscheme.permanent=true"
|
||||
|
||||
# 可选:添加速率限制
|
||||
- "traefik.http.routers.nghttpx.middlewares=rate-limit@docker"
|
||||
- "traefik.http.middlewares.rate-limit.ratelimit.average=100"
|
||||
- "traefik.http.middlewares.rate-limit.ratelimit.burst=50"
|
||||
|
||||
networks:
|
||||
traefik:
|
||||
external: true
|
||||
|
||||
volumes:
|
||||
squid_cache:
|
||||
driver: local
|
||||
squid_logs:
|
||||
driver: local
|
||||
|
||||
```
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
Executable
+67
@@ -0,0 +1,67 @@
|
||||
|
||||
|
||||
|
||||
```
|
||||
services:
|
||||
traefik:
|
||||
image: traefik:v3.4
|
||||
container_name: traefik
|
||||
restart: unless-stopped
|
||||
security_opt:
|
||||
- no-new-privileges:true
|
||||
networks:
|
||||
- proxy
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
- "8080:8080"
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
- ./certs:/certs
|
||||
- ./dynamic:/dynamic
|
||||
|
||||
command:
|
||||
# Entrypoints
|
||||
- "--entrypoints.web.address=:80"
|
||||
- "--entrypoints.websecure.address=:443"
|
||||
- "--entrypoints.websecure.http.tls=true"
|
||||
|
||||
# Providers
|
||||
- "--providers.file.filename=/dynamic/tls.yaml"
|
||||
- "--providers.docker=true"
|
||||
- "--providers.docker.exposedbydefault=false"
|
||||
- "--providers.docker.network=proxy"
|
||||
|
||||
# API & Dashboard
|
||||
- "--api.dashboard=true"
|
||||
- "--api.insecure=false"
|
||||
|
||||
# Logs
|
||||
- "--log.level=INFO"
|
||||
- "--accesslog=true"
|
||||
- "--metrics.prometheus=true"
|
||||
|
||||
# Let's Encrypt (ACME)
|
||||
- "--certificatesresolvers.letsencrypt.acme.email=zhiqiang@windy.me"
|
||||
- "--certificatesresolvers.letsencrypt.acme.storage=/certs/acme.json"
|
||||
- "--certificatesresolvers.letsencrypt.acme.httpchallenge=true"
|
||||
- "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web"
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.http.routers.dashboard.rule=Host(`us4.wsvc.info`)
|
||||
- traefik.http.routers.dashboard.entrypoints=websecure,web
|
||||
- traefik.http.routers.dashboard.service=api@internal
|
||||
- traefik.http.routers.dashboard.tls.certresolver=letsencrypt
|
||||
- "traefik.http.middlewares.dashboard-auth.basicauth.users=admin:$$apr1$$aBNLDToX$$nIKWMN41tGMBhtdSaA/Ih/"
|
||||
- traefik.http.routers.dashboard.middlewares=dashboard-auth@docker,redirect-to-https@file
|
||||
|
||||
networks:
|
||||
proxy:
|
||||
name: proxy
|
||||
external: true
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
S3cureP@ssw0rd!
|
||||
```
|
||||
Reference in New Issue
Block a user