Committable VPS artifacts for the native reverse-tunnel (no live-ops, no secrets):
- gen-device-ca.sh: EC P-256 self-signed device CA (CA:TRUE pathlen:0, keyCertSign+cRLSign),
openssl ca db + empty CRL, idempotent, --kind frp-client scaffolds the control-channel CA.
- issue-device-cert.sh: P-256 leaf, EKU=clientAuth only, 825d, emits .p12 (-legacy) + .pem/.key/.fullchain,
copy_extensions=none prevents CSR-injected serverAuth/CA:TRUE; CN traversal guard.
- revoke-device.sh: openssl ca revoke -> regenerate crl.pem (revocation enforced via -crl_check).
- frp/{frps.toml.example,frpc.example.toml}: control-channel mTLS+token, disableCustomTLSFirstByte=true.
- nginx/frp-mtls.conf: :8470 TLS-term, ssl_verify_client on + device-CA + ssl_crl, WS-upgrade proxy to :7080.
- nginx/stream-sni-additions.md: the two additive SNI map lines (merge-only, coexistence-safe).
Verified: gen->issue->openssl verify->revoke->CRL chain green in a tmp dir (OpenSSL 3.0.18).
2.1 KiB
Stream SNI additions (Native mTLS tunnel · V5)
Two SNI routes must be merged into the existing stream { map $ssl_preread_server_name … }
block on the VPS (/etc/nginx/stream-relay.conf). They add the frp control channel and the
*.terminal data path to the single shared :443 ssl_preread listener.
This is a MERGE, not a file to ship. Do not drop a full stream conf here — that would clobber the live one. Only the two
mapbody lines below are new.
The two additive lines
Add these inside the existing map body (exact match wins over wildcard, so order is not
load-bearing, but keep the exact frp.terminal line above the *.terminal wildcard for clarity):
frp.terminal.yaojia.wang 127.0.0.1:7000; # frps control channel (TLS passthrough)
*.terminal.yaojia.wang 127.0.0.1:8470; # nginx :8470 TLS-term + device-CA mTLS (frp-mtls.conf)
Coexistence warning (do NOT retype the existing lines)
The existing map body already contains — and MUST be preserved verbatim:
# ... existing hostnames directive ...
*.term.yaojia.wang 127.0.0.1:8443; # E2E browser relay — DO NOT RETYPE / REORDER
default 127.0.0.1:10443; # xray Reality — DO NOT RETYPE / REORDER
*.term.yaojia.wang(browser relay) and*.terminal.yaojia.wang(this tunnel) are different parent labels —termvsterminal.ssl_prereadmatches the full SNI, so they never collide.- Re-type nothing you did not author. Capture the current body first
(
nginx -T | sed -n '/map \$ssl_preread_server_name/,/}/p'), then append only the two lines above.
Deploy gate
cp /etc/nginx/stream-relay.conf{,.bak.$(date +%s)} # snapshot first
# ...edit: append the two lines into the map body...
nginx -t && systemctl reload nginx # NEVER reload on a failed -t
After reload, run the 4-zone SNI oracle (openssl s_client -servername … for
frp.terminal / <name>.terminal / <name>.term / default) to confirm all four routes still
resolve to the right backend (PLAN V5 / M1 #7).