'use strict'; /** * 公网网关:只把 WhatsApp webhook 和帮助中心暴露给 Cloudflare Tunnel, * 其余路径(尤其 /api/v1/* 管理接口、admin UI)一律 404,避免整站公网裸奔。 * * cloudflared (quick tunnel) -> public-gateway:9001 -> libredesk:9000 */ const http = require('http'); const PORT = Number(process.env.PORT || 9001); const UPSTREAM = new URL(process.env.UPSTREAM || 'http://libredesk:9000'); // 公网允许的路径前缀 const ALLOW = [ '/webhooks/whatsapp/', // Meta 回调 '/hc/', // 帮助中心(AI 引用链接) '/widget.js', '/widget', // widget iframe 页面 '/static/public/', // widget 静态资源 ]; function allowed(pathname) { return ALLOW.some((p) => pathname === p || pathname.startsWith(p)); } const server = http.createServer((req, res) => { const pathname = (req.url || '/').split('?')[0]; if (!allowed(pathname)) { res.writeHead(404, { 'content-type': 'text/plain; charset=utf-8' }); res.end('not found'); return; } const headers = { ...req.headers }; delete headers.host; headers.host = UPSTREAM.host; const proxy = http.request( { protocol: UPSTREAM.protocol, hostname: UPSTREAM.hostname, port: UPSTREAM.port || 80, method: req.method, path: req.url, headers, }, (upRes) => { res.writeHead(upRes.statusCode || 502, upRes.headers); upRes.pipe(res); } ); proxy.on('error', (err) => { console.error('[public-gateway] upstream error', pathname, err.message); if (!res.headersSent) res.writeHead(502, { 'content-type': 'text/plain; charset=utf-8' }); res.end('bad gateway'); }); req.pipe(proxy); }); server.listen(PORT, '0.0.0.0', () => { console.log(`[public-gateway] listening :${PORT} -> ${UPSTREAM.origin} (allow: ${ALLOW.join(', ')})`); });