docs(us4): sing-box :6443 代理 + 根盘回收 91%→43% (Plane VPS-99/100)
新增独立 HTTPS forward proxy:Traefik 新 entrypoint proxyin(:6443) 终止 TLS, 后端 sing-box(HTTP inbound + users 认证 + direct 出站),与既有 :443 nghttpx/squid 链路并存。宿主机只新增 6443/tcp;容器不发布 host 端口。 新增 compose/sing-box/(镜像 digest 钉版)与两份 runbook: - proxy-health.md::443/:6443 只读健康检查,含开放代理负向测试 - proxy-client-setup.md:curl / env / 浏览器扩展配置与三类失败排查 (407 无认证头、页面加载不全=CDN 域名漏配、urllib/wget 不支持 TLS-to-proxy) 同批根盘回收 91%→43%(约 14G):rust/node/.go/podman 孤儿存储/apt/journal/ 未用镜像/容器日志;journald 加 SystemMaxUse=200M;nghttpx+squid+traefik 加 json-file 轮转 10m×3;删除 ~/.cargo 后修好 zshenv/bashrc/profile 的失效 source。 验证::6443 LE 证书、匿名 407、CONNECT 与绝对 URI 均返回 185.201.226.122; us4-gate 401 / update 200 / trlm 302;8 容器全部 Up;validate-repo.sh PASS。
This commit is contained in:
+127
-2
@@ -52,7 +52,8 @@ do not build its firewall allowlist from the WireGuard role alone.
|
||||
| TCP `3000` | Semaphore UI direct Docker publish | Open; redundant with the Traefik route and should be removed or bound to loopback |
|
||||
| TCP `8080` | Traefik direct Docker publish | Open; redundant with the authenticated dashboard route and should be removed or bound to loopback |
|
||||
| UDP `51820` | WireGuard | Required public endpoint |
|
||||
| TCP `9443` | Host nghttpx-to-Squid proxy | Listening but blocked by the current firewall |
|
||||
| TCP `6443` | Traefik `proxyin` entrypoint → `sing-box` HTTP proxy (`/opt/sing-box`) | Open (Docker publish); added 2026-10-01, VPS-99 |
|
||||
| TCP `9443` | Host nghttpx-to-Squid proxy — **legacy, retirement pending** (see HTTPS forward proxy below) | Listening but blocked by the current firewall |
|
||||
| UDP `123` | ntpsec | Listening but blocked by the current firewall |
|
||||
|
||||
PostgreSQL (`5433`/`5434`/`5435`), MariaDB (`3306`), and the host Squid TCP
|
||||
@@ -77,6 +78,93 @@ and reverify Docker routing. Tracking: Linear `W1N-60`.
|
||||
has no global IPv6 address or IPv6 default route. Treat that as a separate
|
||||
secondary-MX reachability issue.
|
||||
|
||||
## HTTPS forward proxy (verified 2026-09-26)
|
||||
|
||||
The canonical HTTPS forward proxy on this host is:
|
||||
|
||||
| Item | Value |
|
||||
|------|-------|
|
||||
| Endpoint | `https://us4.wsvc.info:443` (Traefik TLS, ACME-managed) |
|
||||
| Chain | Traefik `:443` `HostSNI(us4.wsvc.info)` → container `nghttpx-proxy:3000` (no-TLS) → `squid-backend:3128` |
|
||||
| Config source | `/opt/nghttpx/compose.yml`, `nghttpx.conf`, `squid.conf` (server files are authoritative; not yet repo-owned) |
|
||||
| Credential | `/opt/nghttpx/passwords`, owner `root:proxy` (`0:13`) mode `0640`, bcrypt (`$2y$`, cost 12). Squid reads it through a read-only bind mount; the helper runs as `13:13`, so any permission change must keep group `proxy` read access. |
|
||||
| Username | `windy` |
|
||||
| Password | **Not stored in this repository or Plane.** The plaintext lives only in the operator's password manager; the server holds the bcrypt hash. Rotate with `htpasswd -B -C 12`, validate against `basic_ncsa_auth` before replacing the file, then `docker stop squid-backend` → write in place → `docker start squid-backend` (a rename would break the bind mount). |
|
||||
| Auth behaviour | No/incorrect credentials → `407`; correct credentials → tunnel. Verified egress IP `185.201.226.122` |
|
||||
| Destination policy | HTTPS-tunnel only: `Safe_ports`/`SSL_ports` = `443`; CONNECT to other ports and destinations in `127/8`, `10/8`, `172.16/12`, `192.168/16`, `169.254/16` (metadata), `100.64/10`, `224/4`, `::1`, `fc00::/7`, `fe80::/10`, `ff00::/8` return `403` `ERR_ACCESS_DENIED` |
|
||||
| Limitation | Plain-HTTP (absolute-URI) proxying is **not** supported; non-CONNECT requests fail with `400`. Clients must use HTTPS URLs. |
|
||||
| Credential scope | No longer shared with `us2.wsvc.info` (the two hosts had an identical `/opt/nghttpx/passwords` hash before 2026-09-26; us4 now has its own) |
|
||||
|
||||
Client settings (username `windy`, password from the password manager):
|
||||
|
||||
```text
|
||||
Proxy type: HTTP/HTTPS proxy (CONNECT)
|
||||
Host: us4.wsvc.info
|
||||
Port: 443
|
||||
Username: windy
|
||||
Password: <from password manager>
|
||||
```
|
||||
|
||||
`curl` equivalent (replace `$PROXY_PASSWORD` from the password manager; never inline it in shell history on a shared host):
|
||||
|
||||
```bash
|
||||
curl -x https://us4.wsvc.info:443 -U "windy:$PROXY_PASSWORD" https://api.ipify.org
|
||||
# expected: 185.201.226.122
|
||||
```
|
||||
|
||||
The `9443` path (`nghttpx.service` → host `squid.service` on `127.0.0.1:3128`) is a legacy
|
||||
stack: its certbot-issued certificate expired 2026-01-11, the host Squid has no
|
||||
authentication at all, and no historical client traffic was found in the nghttpx access
|
||||
log. It is blocked by the firewall and reachable only from the host itself. Retirement
|
||||
(stop + disable both units, keep config for rollback) is pending.
|
||||
|
||||
Rollback material from the 2026-09-26 change: `/opt/nghttpx/backups/20260926T091907+0800`
|
||||
(mode `0700`, includes the pre-change password file). Keep it protected and delete it once
|
||||
the change is accepted.
|
||||
|
||||
### Independent `sing-box` proxy on `:6443` (added 2026-10-01, VPS-99)
|
||||
|
||||
A second, independent HTTPS forward proxy on `6443`. It does not touch the `:443`
|
||||
chain above, and the `:443`/`:9443` stacks keep running.
|
||||
|
||||
| Item | Value |
|
||||
|------|-------|
|
||||
| Endpoint | `https://us4.wsvc.info:6443` (Traefik TLS, ACME-managed) |
|
||||
| Chain | Traefik TCP router `singbox-proxy` (entrypoint `proxyin`, `HostSNI(us4.wsvc.info)`, `tls=true`, resolver `letsencrypt`) → `sing-box:8080` |
|
||||
| Config source | `/opt/sing-box/compose.yml` + `config.json` (server authoritative); repo copy `compose/sing-box/compose.yml` |
|
||||
| Image | `ghcr.io/sagernet/sing-box:v1.14.2@sha256:afbffd294c5eb3519cc7b4587299ef189bb0a2ca2f667cb6301fdb6b9bce9558` |
|
||||
| Credential | sing-box `users` in `config.json` (mode `0600`); operator copy in `/opt/sing-box/.proxy-password`. Not in this repo or Plane. |
|
||||
| Capability | Supports **both** CONNECT tunnels and absolute-URI plain-HTTP requests, unlike the `:443` path |
|
||||
| Host port | The container publishes no port; `6443` is bound by Traefik |
|
||||
|
||||
Traefik changes live in `/opt/traefik/compose.yml`:
|
||||
`--entrypoints.proxyin.address=:6443` plus the `6443:6443` publish. Changing either
|
||||
requires recreating the Traefik container (`docker compose up -d`), not
|
||||
`docker compose restart`.
|
||||
|
||||
`6443` was free before the change (nothing listening; `nginx` inactive,
|
||||
`certbot`/`apache2` failed). Docker-published ports land in the firewalld `docker`
|
||||
zone, not `public`, so a public-zone `--add-port=6443` is neither needed nor
|
||||
effective; source restriction belongs in the `DOCKER-USER` chain or a Traefik TCP
|
||||
middleware. `6443` is a public TCP port beyond the target exposure recorded in
|
||||
Plane VPS-47 and still needs an explicit amendment there.
|
||||
|
||||
Client notes — full detail in
|
||||
[runbooks/proxy-client-setup.md](../runbooks/proxy-client-setup.md):
|
||||
|
||||
- The client's proxy type must be **HTTPS** (TLS to the proxy). A plaintext HTTP
|
||||
proxy entry reaches Traefik in cleartext and gets `404`, not a proxied request.
|
||||
- Browser extensions (Zero Omega / SwitchyOmega) must have the username and
|
||||
password saved in the proxy profile, and the routing conditions must include
|
||||
the site's CDN hostnames (for `x.com`: `twimg.com`, `api.x.com`, `t.co`), not
|
||||
only the landing domain — otherwise the page loads incompletely while the
|
||||
server-side log shows no `inbound connection to` line for those hosts.
|
||||
- `python3 urllib` and `wget` cannot speak TLS to a proxy and fail with
|
||||
`Tunnel connection failed: 404 Not Found`.
|
||||
- Client-side symptoms are diagnosed from the server with
|
||||
`docker logs -f sing-box | grep 'inbound connection to'`; `no
|
||||
Proxy-Authorization header` means the client sent no credentials.
|
||||
|
||||
## Safety
|
||||
|
||||
- Private keys, preshared keys, peer configuration files, and QR codes remain
|
||||
@@ -144,6 +232,10 @@ ansible-playbook playbooks/wireguard-harden.yml --limit wireguard \
|
||||
-e '{"wireguard_harden_confirm": true}'
|
||||
```
|
||||
|
||||
Forward-proxy health for both endpoints (`:443` and `:6443`) is read-only:
|
||||
follow [runbooks/proxy-health.md](../runbooks/proxy-health.md). No proxy
|
||||
credential is stored in this repository.
|
||||
|
||||
## Verification
|
||||
|
||||
- Container `wireguard` is running and interface `wg0` exists.
|
||||
@@ -175,7 +267,8 @@ Open host-level follow-up (do not conflate these with a WireGuard outage):
|
||||
1. **Disk capacity:** `/` was 90% used with about 3.4 GiB free. Docker reported
|
||||
about 2.48 GB of reclaimable images and the system journal used about 1.9
|
||||
GB, but do not prune or vacuum without reviewing retention and rollback
|
||||
needs first.
|
||||
needs first. — **Resolved 2026-09-26 (91% → 43%); see *Root disk recovery*
|
||||
below.**
|
||||
2. **Docker exposure:** the firewalld public-zone cleanup is complete, but
|
||||
Docker still publishes `3000` and `8080` outside the ordinary host INPUT
|
||||
path. Remove those redundant Compose bindings in separate maintenance units
|
||||
@@ -191,3 +284,35 @@ Open host-level follow-up (do not conflate these with a WireGuard outage):
|
||||
limit and uses Docker's `json-file` log driver without a per-container
|
||||
rotation setting. Current log size was small, but limits/rotation should be
|
||||
considered during a reviewed Compose update.
|
||||
|
||||
## Root disk recovery (2026-09-26, Plane VPS-100)
|
||||
|
||||
`/` went from **91% used (3.0G free)** to **43% (18G free)** — about 14G
|
||||
reclaimed, following [runbooks/host-disk-cleanup.md](../runbooks/host-disk-cleanup.md).
|
||||
|
||||
Removed: `~/.nvm` 2.6G, `~/.go` 1.9G, `~/.rustup` 1.4G, `~/.cargo` 505M,
|
||||
`~/.npm` 78M, stale rootless-podman storage under `~/.local/share/containers`
|
||||
1.7G, `~/sigstore` 953M, `~/softz` 910M, `~/.cache` 295M, apt archives 613M,
|
||||
the container JSON logs (594M → 320K), and six unreferenced Docker images
|
||||
(`postgres:17`, `postgres:18`, `traefik:v3.4`, `zadam/trilium:0.60.4`,
|
||||
`linuxserver/wireguard:latest`, `traefik/whoami:latest` — all re-pullable).
|
||||
|
||||
Durable changes, not just deletions:
|
||||
|
||||
- `journalctl --vacuum-size=100M` plus drop-in
|
||||
`/etc/systemd/journald.conf.d/00-disk-us4.conf` (`SystemMaxUse=200M`);
|
||||
journald was restarted so the cap is effective (journal back to 83M). Without
|
||||
this the journal regrows toward its default 10%-of-filesystem limit.
|
||||
- Log rotation `max-size: 10m` / `max-file: 3` added to `nghttpx-proxy`,
|
||||
`squid-backend` (`/opt/nghttpx/compose.yml`) and `traefik`
|
||||
(`/opt/traefik/compose.yml`); both stacks were recreated and verified. This
|
||||
closes the unbounded `json.log` growth for these containers.
|
||||
- `~/.zshenv`, `~/.bashrc`, `~/.profile` and `~/.zshrc` had their `~/.cargo/env`
|
||||
and nvm references commented out after those trees were deleted; backups are
|
||||
`~/.<file>.bak-20260926-disk`. Also note `~/.go/bin/cosign` was removed and is
|
||||
re-installable.
|
||||
|
||||
Deliberately kept: `~/.local/share/trilium-data` (88M) is a 2022 Trilium
|
||||
database, not a cache. Still removable if unneeded: `/opt/zeroclaw/target`
|
||||
1.4G, `/opt/trilium-linux-x64-server` 592M (2023 host install, unit disabled),
|
||||
`/opt/go` 167M (2017).
|
||||
|
||||
Reference in New Issue
Block a user