新增独立 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。
8.5 KiB
Runbook: us4 forward proxy health check
Purpose
Read-only health check for the HTTPS forward proxies on us4.wsvc.info: the
canonical :443 path (Traefik TCP SNI → nghttpx → Squid) and the independent
:6443 path (Traefik TCP SNI → sing-box). Confirms TLS, authentication, egress
identity, and that neither endpoint is an open proxy.
Scope
- Applicable:
us4.wsvc.infoonly — Traefik containers, the/opt/nghttpxproject (:443path) and the/opt/sing-boxproject (:6443). - Applicable: verifying that no unauthenticated or wrong-credential request is proxied, and that private/metadata destinations are refused.
- Not applicable: any change to Traefik, nghttpx, Squid, or sing-box configuration — this runbook is read-only; changes go through network-change.md with a change record.
- Not applicable: client-side proxy configuration and browser symptoms (missing credentials, incomplete page loads, TLS-to-proxy support) — use proxy-client-setup.md.
- Not applicable: host firewall, WireGuard, or the
:9443legacy host path retirement (see Plane VPS-98).
Ownership
- Owner: personal ops (Windy)
- Last reviewed: 2026-10-01
- Related systems: us4 (
/opt/traefik,/opt/nghttpx,/opt/sing-box)
Safety
Stop conditions
- Live state contradicts the expected topology below →
STOP, record evidence, change nothing in this runbook. - Any request without a credential, or with a wrong credential, returns proxied
content instead of
407→STOPimmediately: treat the endpoint as an open proxy, keep the evidence, and escalate before any other action. - A private, loopback, link-local, or metadata destination is reachable through
the proxy →
STOPand escalate. - An expected listener (
:6443,:443, or sing-box:8080inside its network) is missing, or a container is restart-looping →STOP; do not "fix it in place" from this runbook.
Expected topology
| Endpoint | Chain | Credential |
|---|---|---|
us4.wsvc.info:443 |
Traefik TCP router ng-gateway (entrypoint websecure, HostSNI(us4.wsvc.info), tls=true, resolver letsencrypt) → nghttpx-proxy:3000 → squid-backend:3128 |
Squid bcrypt (/opt/nghttpx/passwords) |
us4.wsvc.info:6443 |
Traefik TCP router singbox-proxy (entrypoint proxyin, HostSNI(us4.wsvc.info), tls=true, resolver letsencrypt) → sing-box:8080 |
sing-box users in /opt/sing-box/config.json |
host :9443 |
host nghttpx.service → host Squid :3128 |
none (legacy, firewall-blocked) |
Known limitation of the :443 path: nghttpx is CONNECT-only and answers 400
to absolute-URI plain-HTTP requests. The :6443 sing-box path supports both.
Pass criteria
docker psshowstraefik,sing-box,nghttpx-proxy,squid-backendrunning, withsing-boxandtraefikrestart counts not increasing.docker inspect traefik --format '{{json .Config.Cmd}}'contains--entrypoints.proxyin.address=:6443.- TLS on
:6443serves a valid Let's Encrypt certificate forus4.wsvc.info(not the self-signed default certificate). - No credential →
407; wrong credential →407; plain HTTP to:6443→ TLS handshake failure. - Authenticated request through
:6443returns egress IP185.201.226.122for both an HTTPS (CONNECT) target and an HTTP (absolute-URI) target. - Authenticated request through
:443returns the same egress IP (CONNECT target only). https://us4-gate.wsvc.infostill answers (dashboard, basic auth →401), and theupdate/trlmsites are unaffected.
Procedure
Step 1 — Container and listener state
Action
ssh -4 windy@us4.wsvc.info
docker ps --format '{{.Names}}\t{{.Status}}\t{{.Ports}}'
docker inspect traefik --format '{{json .Config.Cmd}}'
sudo ss -ltnp | grep -E ':(6443|443|9443)\b'
Expected
traefik publishing 6443, sing-box running with no host port, and the
proxyin entrypoint present in Traefik's command.
Decision
- All present → Step 2.
- Anything missing or restart-looping →
STOPand record the evidence.
Step 2 — TLS certificate
Action
openssl s_client -connect us4.wsvc.info:6443 -servername us4.wsvc.info </dev/null 2>/dev/null \
| openssl x509 -noout -subject -issuer -dates -ext subjectAltName
Expected
subject=CN=us4.wsvc.info, issuer Let's Encrypt, notAfter in the future.
Decision
- Valid LE certificate → Step 3.
- Self-signed default certificate, expired certificate, or handshake failure →
STOP; the certificate is issued on demand, so retry once before concluding.
Step 3 — Negative authentication tests (run from an external client)
Action
# no credential
curl -sS -o /dev/null -w '%{http_code}\n' --max-time 15 \
--proxy https://us4.wsvc.info:6443 https://example.com
# wrong credential
curl -sS -o /dev/null -w '%{http_code}\n' --max-time 15 \
--proxy https://us4.wsvc.info:6443 --proxy-user 'windy:definitely-wrong' https://example.com
# plain HTTP to the TLS port
curl -sS -o /dev/null -w '%{http_code}\n' --max-time 8 http://us4.wsvc.info:6443/
Expected
The two proxy attempts fail authentication (407, or a curl CONNECT abort), and
the plain-HTTP attempt fails the TLS handshake.
Decision
- All rejected → Step 4.
- Any of them returns proxied content →
STOPimmediately (open proxy).
Step 4 — Positive path and egress identity
Action — supply the credential from its server-side source; never paste it into Plane, the repo, or a shared transcript.
# on us4, for :6443 (CONNECT target and absolute-URI HTTP target)
PW="$(sudo cat /opt/sing-box/.proxy-password)"
curl -sS --proxy https://us4.wsvc.info:6443 --proxy-user "windy:$PW" https://ipinfo.io/ip
curl -sS --proxy https://us4.wsvc.info:6443 --proxy-user "windy:$PW" http://ipinfo.io/ip
# on us4, for the :443 path
curl -sS --proxy https://us4.wsvc.info:443 --proxy-user 'windy:<password>' https://ipinfo.io/ip
Expected
185.201.226.122 on all successful requests.
Decision
- Expected egress IP → Step 5.
407with the known-good credential →STOP; checkdocker logs sing-boxfor the inbound user list before touching configuration.
Step 5 — Regression on existing HTTPS sites
Action
for h in us4-gate.wsvc.info update.wsvc.info trlm.wsvc.info; do
printf '%s ' "$h"
curl -sS -o /dev/null -w '%{http_code}\n' --max-time 15 "https://$h"
done
Expected
us4-gate → 401 (dashboard basic auth), update → 200, trlm → 302
redirecting to /login. A 302 is a healthy application response, not a
failure.
Decision
- Expected codes → health check passes.
- Any other code →
STOP; a Traefik recreate may have failed, checkdocker logs traefik.
Troubleshooting
Troubleshooting A — 407 with the correct credential
- Evidence:
docker logs sing-boxshows the HTTP inbound rejecting the user. - Allowed: read-only inspection of
/opt/sing-box/config.json(mode 0600) to confirm the username matches; compare with the client's username. - Next: if the password itself is wrong, rotate it as a change (regenerate
on-host, update
config.json,docker compose up -d), then re-run Step 4. Do not paste the new password into Plane or the repo.
Troubleshooting B — tunnel establishes but no traffic flows
- Evidence:
docker logs sing-box, anddocker exec sing-box nslookup <host>. - Allowed: read-only checks. Confirm the container resolves and reaches the
internet, and that
route.finalpoints at thedirectoutbound. - Next: if DNS resolution fails, compare against the other containers on the
proxynetwork; do not addinternal: trueto the network (it removes egress and the proxy will accept connections but never reach destinations).
Final Verification
- All five steps pass.
- No credential appears in Plane, the repo, or the terminal transcript.
- Result and any deviation recorded on Plane VPS-99.
References
- hosts/us4.wsvc.info.md
- proxy-client-setup.md — client-side setup and triage
- compose/sing-box/compose.yml
- network-change.md, rollback.md
- Plane VPS-99 (this proxy), VPS-98 (
:443path audit), VPS-47 (public port exposure target) - Traefik TCP TLS: https://doc.traefik.io/traefik/v3.4/reference/routing-configuration/tcp/tls/
- sing-box HTTP inbound: https://sing-box.sagernet.org/configuration/inbound/http/