musify-proxy

Proxy inverso transparente (Express + http/https nativo). Reenvia peticiones HTTP a cualquier destino y devuelve la respuesta sin transformarla: status, headers, cookies y body.

comprobando /health...

URL base y enrutado

Este deployment expone el proxy bajo el prefijo /proxy.

https://ESTE-HOST/proxy/<ruta-del-destino>?<query>

El destino se elige por peticion con el header x-target-url. Si el servidor tiene TARGET_URL configurada y no envias el header, se usa esa. Si no hay ninguna de las dos: 400 TARGET_REQUIRED.

# El upstream recibe: https://www.deezer.com/users/1?x=1
curl "https://ESTE-HOST/proxy/users/1?x=1" \
  -H "x-target-url: https://www.deezer.com"

La ruta y la query que siguen al prefijo se concatenan tal cual al destino. El header x-target-url nunca llega al upstream.

Que acepta

Metodos

GETPOSTPUT PATCHDELETEOPTIONS HEAD

OPTIONS con Access-Control-Request-Method (preflight CORS) se responde localmente con 204. Un OPTIONS normal se reenvia al upstream.

Body

El body se captura como Buffer crudo y se reenvia byte a byte, sin parsear ni re-serializar:

TipoEjemplo
JSONContent-Type: application/json
Formularioapplication/x-www-form-urlencoded
Archivosmultipart/form-data (no fijes el Content-Type a mano: deja que FormData genere el boundary)
Texto / Binariocualquier text/* u application/octet-stream

Limite de tamano del body: configurable en el servidor (por defecto 50mb). Al superarlo responde 413.

Headers

Se reenvian todos (Authorization, Cookie, Origin, Referer, Accept, User-Agent, etc.) excepto los hop-by-hop (host, connection, content-length, transfer-encoding, keep-alive, upgrade, te, trailer, expect, proxy-*) y el propio x-target-url. Se anaden X-Forwarded-For/Proto/Host.

Respuesta

Status, headers y multiples Set-Cookie se devuelven tal cual. El body se transmite en streaming (vale para JSON y para descargas grandes).

Cookies

El header Cookie del cliente se reenvia integro, y las Set-Cookie del upstream vuelven sin fusionarse (una por cookie).

Errores

StatuscodeCuando
400TARGET_REQUIREDSin header x-target-url y sin TARGET_URL configurada
400TARGET_INVALIDEl destino no es una URL http/https valida
403TARGET_BLOCKEDDestino a red privada con BLOCK_PRIVATE_TARGETS=true
413entity.too.largeBody mayor que BODY_LIMIT
502UPSTREAM_UNREACHABLENo se pudo conectar con el destino
502UPSTREAM_TIMEOUTEl destino no respondio dentro del timeout

Formato de error: {"error":"...","code":"...","message":"..."}

Ejemplos

Deezer gw-light (registro/login)

curl -X POST "https://ESTE-HOST/proxy/ajax/gw-light.php?method=deezer_userAutolog&input=3&api_version=1.0&api_token=&cid=123" \
  -H "x-target-url: https://www.deezer.com" \
  -H "Content-Type: application/json" \
  -H "Origin: https://www.deezer.com" \
  -H "Referer: https://www.deezer.com/" \
  -d '{"APP_NAME":"deezer-web","AUTHORIZE_UNLOGGED":true,"CHECKFORM":true,"DEVICE_TOKEN":"abc"}'

Deezer pipe (GraphQL)

curl -X POST "https://ESTE-HOST/proxy/api" \
  -H "x-target-url: https://pipe.deezer.com" \
  -H "Content-Type: application/json" \
  -H "Origin: https://www.deezer.com" \
  -H "Referer: https://www.deezer.com/" \
  -d '{"query":"{ __typename }"}'

fetch / axios desde la app

// fetch
await fetch("https://ESTE-HOST/proxy/users/1", {
  headers: { "x-target-url": "https://www.deezer.com" },
});

// axios
const api = axios.create({
  baseURL: "https://ESTE-HOST/proxy",
  headers: { "x-target-url": "https://www.deezer.com" },
});

Subir archivo (multipart)

const form = new FormData();
form.append("file", file);
form.append("name", "hola");
await fetch("https://ESTE-HOST/proxy/upload", {
  method: "POST",
  headers: { "x-target-url": "https://tu-api.com" },
  body: form, // no fijes Content-Type manualmente
});

Descargar archivo

const res = await fetch("https://ESTE-HOST/proxy/files/123", {
  headers: { "x-target-url": "https://tu-api.com" },
});
const blob = await res.blob();

Playground

Prueba peticiones desde el navegador contra este mismo proxy.

Notas

- No soporta WebSockets (los headers Upgrade/Connection se eliminan).

- No sigue redirects: los devuelve tal cual al cliente.

- El timeout al upstream es configurable en el servidor (por defecto 30s).

- Logs del servidor: solo metodo, ruta sin query y status. Nunca headers ni tokens.

- Si el proxy esta abierto a Internet, protegelo con PROXY_API_KEY (ver bloque comentado en index.js) y activa BLOCK_PRIVATE_TARGETS=true.