# A3 integration nginx.conf — exercises the REAL binding stack end-to-end: getCertSub.js (njs), # js_set $cert_sub, the $cert_host_ok map, and the single `if → return 403`. # # ONLY delta from the production deploy/nginx/frp-mtls.conf: the location returns a stub `200 ok` # instead of proxying to the frps vhost (no frps needed to prove the AUTH gate), and the listener is # a plain :8470 (not 127.0.0.1) so the published container port is reachable. The binding logic — # ssl_verify_client + njs SAN parse + map + if→403 — is byte-identical to prod. load_module modules/ngx_http_js_module.so; # VPS prereq (main context) events {} http { js_import certsub from njs/getCertSub.js; # mounted at /etc/nginx/njs/getCertSub.js js_set $cert_sub certsub.getCertSub; map "$cert_sub:$ssl_server_name" $cert_host_ok { "~^(?[^:]+):(?P=s)\." 1; default 0; } server { listen 8470 ssl; server_name ~^.+\.terminal\.yaojia\.wang$; ssl_certificate /certs/server.crt; ssl_certificate_key /certs/server.key; # data-path gate: only device-CA-signed client certs get past the handshake ssl_verify_client on; ssl_client_certificate /certs/ca.crt; ssl_verify_depth 1; # A3 cert→Host binding — the one `if` guarding the single return; rule lives in the map. if ($cert_host_ok = 0) { return 403; } location / { return 200 "ok\n"; } # PROD: proxy_pass http://127.0.0.1:7080; (frps vhost) } }