feat: add restricted Supabase reverse proxy for Timeweb
This commit is contained in:
parent
a206cfd1f1
commit
18ef6a2e45
74
proxy/server.js
Normal file
74
proxy/server.js
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
import http from 'node:http';
|
||||||
|
import httpProxy from 'http-proxy';
|
||||||
|
|
||||||
|
const PORT = Number(process.env.PORT || 8080);
|
||||||
|
const TARGET = process.env.SUPABASE_TARGET || 'https://cksuehzcimitsxmeloes.supabase.co';
|
||||||
|
const allowedOrigins = new Set([
|
||||||
|
'https://app.caterium.ru',
|
||||||
|
'https://caterium.ru',
|
||||||
|
'https://www.caterium.ru'
|
||||||
|
]);
|
||||||
|
|
||||||
|
const proxy = httpProxy.createProxyServer({
|
||||||
|
target: TARGET,
|
||||||
|
changeOrigin: true,
|
||||||
|
xfwd: true,
|
||||||
|
secure: true,
|
||||||
|
ws: true
|
||||||
|
});
|
||||||
|
|
||||||
|
proxy.on('proxyReq', (proxyReq) => {
|
||||||
|
proxyReq.setHeader('host', new URL(TARGET).host);
|
||||||
|
});
|
||||||
|
|
||||||
|
proxy.on('error', (err, req, res) => {
|
||||||
|
console.error('[proxy:error]', err?.message || err);
|
||||||
|
if (res && !res.headersSent) {
|
||||||
|
res.writeHead(502, {'content-type':'application/json; charset=utf-8'});
|
||||||
|
}
|
||||||
|
try { res?.end(JSON.stringify({error:'upstream_unavailable'})); } catch (_) {}
|
||||||
|
});
|
||||||
|
|
||||||
|
function cors(req, res) {
|
||||||
|
const origin = req.headers.origin;
|
||||||
|
if (origin && !allowedOrigins.has(origin)) return false;
|
||||||
|
if (origin) {
|
||||||
|
res.setHeader('Access-Control-Allow-Origin', origin);
|
||||||
|
res.setHeader('Vary', 'Origin');
|
||||||
|
}
|
||||||
|
res.setHeader('Access-Control-Allow-Credentials', 'true');
|
||||||
|
res.setHeader('Access-Control-Allow-Headers', req.headers['access-control-request-headers'] || 'authorization,apikey,content-type,x-client-info,prefer,range');
|
||||||
|
res.setHeader('Access-Control-Allow-Methods', 'GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const server = http.createServer((req, res) => {
|
||||||
|
if (!cors(req, res)) {
|
||||||
|
res.writeHead(403, {'content-type':'application/json; charset=utf-8'});
|
||||||
|
return res.end(JSON.stringify({error:'origin_not_allowed'}));
|
||||||
|
}
|
||||||
|
if (req.method === 'OPTIONS') {
|
||||||
|
res.writeHead(204);
|
||||||
|
return res.end();
|
||||||
|
}
|
||||||
|
if (req.url === '/health' || req.url === '/healthz') {
|
||||||
|
res.writeHead(200, {'content-type':'application/json; charset=utf-8'});
|
||||||
|
return res.end(JSON.stringify({ok:true,target:'supabase'}));
|
||||||
|
}
|
||||||
|
if (!/^\/(rest|auth|storage|functions|realtime)\/v1(?:\/|\?|$)/.test(req.url || '')) {
|
||||||
|
res.writeHead(404, {'content-type':'application/json; charset=utf-8'});
|
||||||
|
return res.end(JSON.stringify({error:'route_not_allowed'}));
|
||||||
|
}
|
||||||
|
proxy.web(req, res);
|
||||||
|
});
|
||||||
|
|
||||||
|
server.on('upgrade', (req, socket, head) => {
|
||||||
|
const origin = req.headers.origin;
|
||||||
|
if (origin && !allowedOrigins.has(origin)) return socket.destroy();
|
||||||
|
if (!/^\/realtime\/v1(?:\/|\?|$)/.test(req.url || '')) return socket.destroy();
|
||||||
|
proxy.ws(req, socket, head);
|
||||||
|
});
|
||||||
|
|
||||||
|
server.listen(PORT, '0.0.0.0', () => {
|
||||||
|
console.log(`[caterium-proxy] listening on ${PORT} -> ${TARGET}`);
|
||||||
|
});
|
||||||
Loading…
Reference in New Issue
Block a user