[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6H02MP49X4DBVR9F85HZB30":3,"skill-same:01M6H02MP49X4DBVR9F85HZB30":83},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":16,"sourceHtmlUrl":17,"categories":18,"keywords":19,"publishedAt":41,"linkOnly":42,"markdownContent":43,"markdownBody":44,"frontMatter":45,"refName":46,"commitSha":47,"skillDirectory":48,"forksCount":49,"repositoryHtmlUrl":50,"repositoryHomepageUrl":6,"ownerHtmlUrl":51,"ownerBlogUrl":52,"ownerDescription":53,"updatedAt":54,"install":55,"resources":68},"01M6H02MP49X4DBVR9F85HZB30","route-private-traffic-over-a-vpn",null,"Use when services in different private networks must talk without exposing ports publicly, or a developer needs reach into a private subnet. Route private traffic over a VPN or bastion with the correct routes, split tunnel, and DNS instead of publishing the service to the internet.","jiayaoqijia\u002Fcryptoskill","jiayaoqijia","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F1453879?v=4","01M6GMYTX7Q7S504VC6E756ENR","YQ","01M6GMYV1QKJ1CC75MTTGT9PR0",81,"MIT","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fpayments\u002F0xklen-route-private-traffic-over-a-vpn\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fpayments\u002F0xklen-route-private-traffic-over-a-vpn\u002FSKILL.md",[],[20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40],"route private traffic over a vpn","traffic","route","vpn","subnet","talk","when","split","internet","with","service","tunnel","developer","Bastion","publishing","use","ports","correct","networks","dns","services","2026-11-10 10:12:30",false,"---\nname: route-private-traffic-over-a-vpn\ndescription: Use when services in different private networks must talk without exposing ports publicly, or a developer needs reach into a private subnet. Route private traffic over a VPN or bastion with the correct routes, split tunnel, and DNS instead of publishing the service to the internet.\n---\n\n# Route private traffic over a VPN\n\nThe safe way to reach a private service is to join the private network, not to expose the port. Get\nthe routes, split-tunnel policy, and internal DNS right or you will either leak traffic or see nothing.\n\n## Procedure\n\n1. Bring up the tunnel and confirm the peer is reachable:\n   ```bash\n   sudo wg show            # WireGuard handshake + transfer counters\n   ip -br addr show tun0\n   ping -c 3 10.20.0.1     # the private gateway\n   ```\n2. Verify the routes the client installed push your private subnets through the tunnel and nothing else:\n   ```bash\n   ip route show        # expect 10.20.0.0\u002F16 dev tun0; default unchanged for split tunnel\n   ```\n   A default route through `tun0` means full tunnel — all traffic exits the VPN, which may be intended or not.\n3. Confirm internal DNS resolves through the tunnel (see `resolve-split-horizon-dns`):\n   ```bash\n   dig @10.20.0.53 db.internal A +short\n   ```\n   Split tunnel often needs an explicit resolver for the private domain so it is not sent to the public resolver.\n4. Test the actual service, staying inside the private range:\n   ```bash\n   curl -sS --max-time 5 http:\u002F\u002F10.20.1.30:5432\u002Fhealth 2>&1 | head -1\n   ```\n5. For a bastion instead of a mesh VPN, tunnel the port and connect to localhost:\n   ```bash\n   ssh -N -L 5432:10.20.1.30:5432 ec2-user@bastion.internal\n   psql -h 127.0.0.1 -p 5432 -U app mydb\n   ```\n6. Lock the bastion down: key-only auth, an allowlisted source CIDR, and a short session timeout:\n   ```bash\n   ssh -o PasswordAuthentication=no -o ConnectTimeout=5 ec2-user@bastion.internal\n   ```\n7. Record which subnets are routed so a future service on a new subnet is not silently unreachable.\n\n## Pitfalls\n\n- A full-tunnel default route sends all traffic (including public sites) through the VPN, surprising users and overloading the gateway.\n- A VPN that routes packets but provides no internal DNS still fails on hostnames — you debug the wrong layer.\n- Overlapping CIDRs (both sides use `10.0.0.0\u002F16`) mean the client cannot tell which `10.x` to route where.\n- Publishing the DB port publicly \"just for now\" is the exposure the VPN is meant to prevent; a bastion and a temporary rule are not the same thing.\n- Leaving the SSH tunnel open in a screen session exposes the DB to anything on localhost.\n- `ssh -L` binds localhost by default; adding `-g` binds all interfaces and exposes the port on the LAN.\n- WireGuard's `AllowedIPs` both routes traffic *and* filters it; a wrong mask silently drops return packets.\n\n## Verification\n\n    ip route get 10.20.1.30     # must show dev tun0 (or the tunnel)\n    dig @10.20.0.53 db.internal A +short\n    curl -sS --max-time 5 http:\u002F\u002F10.20.1.30:8080\u002Fhealth\n\nPass means the private IP routes through the tunnel, internal DNS resolves, and the service responds\nwithout any public exposure. Report: \"10.20.0.0\u002F16 via tun0, split tunnel (public default intact),\ninternal DNS resolving; service reachable only over VPN.\"\n","# Route private traffic over a VPN\n\nThe safe way to reach a private service is to join the private network, not to expose the port. Get\nthe routes, split-tunnel policy, and internal DNS right or you will either leak traffic or see nothing.\n\n## Procedure\n\n1. Bring up the tunnel and confirm the peer is reachable:\n   ```bash\n   sudo wg show            # WireGuard handshake + transfer counters\n   ip -br addr show tun0\n   ping -c 3 10.20.0.1     # the private gateway\n   ```\n2. Verify the routes the client installed push your private subnets through the tunnel and nothing else:\n   ```bash\n   ip route show        # expect 10.20.0.0\u002F16 dev tun0; default unchanged for split tunnel\n   ```\n   A default route through `tun0` means full tunnel — all traffic exits the VPN, which may be intended or not.\n3. Confirm internal DNS resolves through the tunnel (see `resolve-split-horizon-dns`):\n   ```bash\n   dig @10.20.0.53 db.internal A +short\n   ```\n   Split tunnel often needs an explicit resolver for the private domain so it is not sent to the public resolver.\n4. Test the actual service, staying inside the private range:\n   ```bash\n   curl -sS --max-time 5 http:\u002F\u002F10.20.1.30:5432\u002Fhealth 2>&1 | head -1\n   ```\n5. For a bastion instead of a mesh VPN, tunnel the port and connect to localhost:\n   ```bash\n   ssh -N -L 5432:10.20.1.30:5432 ec2-user@bastion.internal\n   psql -h 127.0.0.1 -p 5432 -U app mydb\n   ```\n6. Lock the bastion down: key-only auth, an allowlisted source CIDR, and a short session timeout:\n   ```bash\n   ssh -o PasswordAuthentication=no -o ConnectTimeout=5 ec2-user@bastion.internal\n   ```\n7. Record which subnets are routed so a future service on a new subnet is not silently unreachable.\n\n## Pitfalls\n\n- A full-tunnel default route sends all traffic (including public sites) through the VPN, surprising users and overloading the gateway.\n- A VPN that routes packets but provides no internal DNS still fails on hostnames — you debug the wrong layer.\n- Overlapping CIDRs (both sides use `10.0.0.0\u002F16`) mean the client cannot tell which `10.x` to route where.\n- Publishing the DB port publicly \"just for now\" is the exposure the VPN is meant to prevent; a bastion and a temporary rule are not the same thing.\n- Leaving the SSH tunnel open in a screen session exposes the DB to anything on localhost.\n- `ssh -L` binds localhost by default; adding `-g` binds all interfaces and exposes the port on the LAN.\n- WireGuard's `AllowedIPs` both routes traffic *and* filters it; a wrong mask silently drops return packets.\n\n## Verification\n\n    ip route get 10.20.1.30     # must show dev tun0 (or the tunnel)\n    dig @10.20.0.53 db.internal A +short\n    curl -sS --max-time 5 http:\u002F\u002F10.20.1.30:8080\u002Fhealth\n\nPass means the private IP routes through the tunnel, internal DNS resolves, and the service responds\nwithout any public exposure. Report: \"10.20.0.0\u002F16 via tun0, split tunnel (public default intact),\ninternal DNS resolving; service reachable only over VPN.\"\n",{"name":5,"description":7},"main","3df1d0d67b30ff15236561f8c0f9f06d33f42dfd","skills\u002Fpayments\u002F0xklen-route-private-traffic-over-a-vpn",17,"https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia","https:\u002F\u002Feth2030.com","Hardcore infra. Building @alt-research and applied cryptography.","2026-11-12 02:28:42",{"source":8,"skillName":5,"commands":56,"prompt":66,"zipAvailable":67},[57,60,63],{"tool":58,"command":59},"npx","npx skills add jiayaoqijia\u002Fcryptoskill --skill route-private-traffic-over-a-vpn",{"tool":61,"command":62},"bunx","bunx skills add jiayaoqijia\u002Fcryptoskill --skill route-private-traffic-over-a-vpn",{"tool":64,"command":65},"pnpm","pnpm dlx skills add jiayaoqijia\u002Fcryptoskill --skill route-private-traffic-over-a-vpn","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fpayments\u002F0xklen-route-private-traffic-over-a-vpn\u002FSKILL.md",true,[69,73,79],{"path":70,"resourceType":70,"resourceTypeDesc":71,"sizeBytes":72,"sourceHtmlUrl":16},"LICENSE","许可证",1063,{"path":74,"resourceType":75,"resourceTypeDesc":76,"sizeBytes":77,"sourceHtmlUrl":78},"SOURCE.md","REFERENCE","参考文档",358,"https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fpayments\u002F0xklen-route-private-traffic-over-a-vpn\u002FSOURCE.md",{"path":80,"resourceType":75,"resourceTypeDesc":76,"sizeBytes":81,"sourceHtmlUrl":82},"TRUST.auto.yaml",2217,"https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fpayments\u002F0xklen-route-private-traffic-over-a-vpn\u002FTRUST.auto.yaml",[84,112,135,153,166,176],{"skillNo":85,"name":86,"nameZh":6,"description":87,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":88,"sourceHtmlUrl":89,"categories":90,"keywords":91,"publishedAt":41},"01M712C436EQYE43342Q4E7GG1","recipe-performance","Diagnose a specific MetaMask user flow's real-app performance and Sentry critical-user-flow telemetry with deterministic mm-harness recipes. Use for CUF boundaries, cold\u002Fwarm\u002Fbackground-resume behavior, latency regressions, lifecycle tags, duplicate or blocking network requests, long tasks, layout\u002Fpaint cost, screen redraws, React rerenders, or browser trace analysis where tests alone cannot prove the real app.","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fwallets\u002Fmetamask-official-recipe-performance\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fwallets\u002Fmetamask-official-recipe-performance\u002FSKILL.md",[],[92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111],"performance","recipe performance","recipe","mm","sentry","harness","app","deterministic","recipes","flow","cold","critical","analysis","tasks","react","browser","layout","screen","network","metamask",{"skillNo":113,"name":114,"nameZh":6,"description":115,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":116,"licenseFileUrl":117,"sourceHtmlUrl":118,"categories":119,"keywords":120,"publishedAt":41},"01M70XT2F8A5CQZ81JBP98KSW3","mexc-spot-websocket","MEXC Spot WebSocket workflows for public streams, protobuf handling, depth maintenance, listen keys, and private streams without exposing API keys.","Apache-2.0","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fexchanges\u002Fmncrftfrcnm-mexc-spot-websocket\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fexchanges\u002Fmncrftfrcnm-mexc-spot-websocket\u002FSKILL.md",[],[121,122,123,124,125,126,127,128,129,130,131,132,133,134],"mexc spot websocket","spot","websocket","api","workflows","public","listen","streams","depth","keys","for","api keys","maintenance","protobuf",{"skillNo":136,"name":137,"nameZh":6,"description":138,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":116,"licenseFileUrl":139,"sourceHtmlUrl":140,"categories":141,"keywords":142,"publishedAt":41},"01M70XT0MBXN3WZY1BKN0CPNKR","mexc-spot-rest","MEXC Spot REST workflows for public data, signed account requests, orders, wallet\u002Fadmin actions, and secure signing without exposing API keys.","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fexchanges\u002Fmncrftfrcnm-mexc-spot-rest\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fexchanges\u002Fmncrftfrcnm-mexc-spot-rest\u002FSKILL.md",[],[143,122,144,145,146,147,148,132,131,130,149,150,151,126,152,125,124],"mexc spot rest","REST","admin","signing","Wallet","requests","actions","secure","data","orders",{"skillNo":154,"name":155,"nameZh":6,"description":156,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":116,"licenseFileUrl":157,"sourceHtmlUrl":158,"categories":159,"keywords":160,"publishedAt":41},"01M70XSYSVZ2N0N91XCAR2CAK0","mexc-futures-websocket","MEXC Futures WebSocket workflows for public streams, private account\u002Forder\u002Fposition streams, ping\u002Fpong, subscriptions, and depth maintenance.","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fexchanges\u002Fmncrftfrcnm-mexc-futures-websocket\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fexchanges\u002Fmncrftfrcnm-mexc-futures-websocket\u002FSKILL.md",[],[161,162,123,163,164,133,131,165,129,128,126,125],"mexc futures websocket","futures","position","ping","subscriptions",{"skillNo":167,"name":168,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":169,"sourceHtmlUrl":170,"categories":171,"keywords":172,"publishedAt":41},"01M6H0ZWHVE5W04WG2DKQE2SQC","0xklen-version-and-refresh-sanctions-lists","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fpayments\u002F0xklen-version-and-refresh-sanctions-lists\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fpayments\u002F0xklen-version-and-refresh-sanctions-lists\u002FSKILL.md",[],[173,174,175],"refresh","0xklen version and refresh sanctions lists","version",{"skillNo":177,"name":178,"nameZh":6,"description":179,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":180,"sourceHtmlUrl":181,"categories":182,"keywords":183,"publishedAt":41},"01M6H0Z28Q3R8J0S799GJQWXM3","verify-tests-cover-changed-lines","Use when a PR adds code that the existing suite may not exercise. Measures patch coverage — the share of newly changed lines hit by tests — before approving.","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fpayments\u002F0xklen-verify-tests-cover-changed-lines\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fpayments\u002F0xklen-verify-tests-cover-changed-lines\u002FSKILL.md",[],[184,185,186,187,188,189,190,35,191,192,193],"tests","cover","verify tests cover changed lines","verify","coverage","pr","exercise","patch","code","share"]