#!/usr/bin/env node /** * Local reverse proxy for plaza.tkmind.cn * HTTPS :443 (default) or HTTP :80 -> Plaza Next.js :3001 * * Requires root on macOS for 443/80: * sudo pnpm dev:plaza-proxy */ import http from 'node:http'; import https from 'node:https'; import fs from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; import { ensurePlazaLocalTls } from './plaza-local-tls.mjs'; const listenHost = process.env.PLAZA_PROXY_BIND ?? '0.0.0.0'; const publicBase = String(process.env.PLAZA_PUBLIC_BASE ?? 'https://plaza.tkmind.cn').replace(/\/$/, ''); const useHttps = publicBase.startsWith('https://'); const listenPort = Number( process.env.PLAZA_PUBLIC_PORT ?? (useHttps ? 443 : 80), ); const targetHost = process.env.PLAZA_PROXY_TARGET ?? '127.0.0.1'; const targetPort = Number(process.env.PLAZA_PORT ?? 3001); const plazaHost = process.env.PLAZA_LOCAL_HOST ?? 'plaza.tkmind.cn'; function proxyHandler(clientReq, clientRes) { const headers = { ...clientReq.headers }; headers.host = `${plazaHost}:${targetPort}`; const proxyReq = http.request( { hostname: targetHost, port: targetPort, method: clientReq.method, path: clientReq.url, headers, }, (proxyRes) => { clientRes.writeHead(proxyRes.statusCode ?? 502, proxyRes.headers); proxyRes.pipe(clientRes); }, ); proxyReq.on('error', (err) => { if (!clientRes.headersSent) { clientRes.writeHead(502, { 'Content-Type': 'text/plain; charset=utf-8' }); } clientRes.end(`Plaza upstream unavailable (${targetHost}:${targetPort}): ${err.message}`); }); clientReq.pipe(proxyReq); } function bindErrorHandler(server) { server.on('error', (err) => { if (err.code === 'EACCES') { console.error(`无法监听 ${listenPort} 端口(需要 root)。请执行:`); console.error(' sudo pnpm dev:plaza-proxy'); process.exit(1); } if (err.code === 'EADDRINUSE') { console.error(`端口 ${listenPort} 已被占用。`); process.exit(1); } throw err; }); } let server; if (useHttps) { const { keyPath, certPath } = ensurePlazaLocalTls(); server = https.createServer( { key: fs.readFileSync(keyPath), cert: fs.readFileSync(certPath), }, proxyHandler, ); } else { server = http.createServer(proxyHandler); } bindErrorHandler(server); server.listen(listenPort, listenHost, () => { const scheme = useHttps ? 'https' : 'http'; const publicUrl = (listenPort === 80 && !useHttps) || (listenPort === 443 && useHttps) ? `${scheme}://${plazaHost}` : `${scheme}://${plazaHost}:${listenPort}`; console.log(`Plaza proxy ${publicUrl} -> http://${targetHost}:${targetPort}`); }); for (const signal of ['SIGINT', 'SIGTERM']) { process.on(signal, () => { server.close(() => process.exit(0)); }); }