EQProxy Load balancer y reverse proxy en Rust

Conversores

eqproxy config import lee una configuración de nginx, HAProxy, ingress-nginx o Envoy y escribe un eqproxy.toml equivalente más un informe que clasifica cada directiva del origen como convertida, a revisar o rechazada.

Es análisis estático: no ejecuta nada de la configuración de origen. Y el resultado se parsea y se valida con el propio parser de EQProxy antes de entregarse, de modo que el conversor no puede devolver un fichero que el producto rechazaría.

Cómo se invoca

eqproxy config import \
  --input haproxy.cfg \
  --output eqproxy.toml \
  --report report.md
OpciónUso
--from nginxnginx, haproxy, ingress (o ingress-nginx) o envoy; si se omite, se detecta por el contenido
--inputFichero de origen
--outputDestino del eqproxy.toml
--reportDestino del informe Markdown

Códigos de salida:

CódigoSignificado
0Conversión limpia: todas las directivas tienen destino o son informativas
2El fichero generado es válido, pero hay directivas rechazadas: el informe las nombra
1No se escribió nada: el origen no se pudo leer o el resultado no pasó la validación

El informe abre con los recuentos —directivas leídas, clasificadas, convertidas, con aviso y rechazadas— y con dos tablas de lo generado (listeners y backends). Después lista las directivas por severidad: no traducible, rechazado (sin equivalente), revisar, informativo y convertido. Cierra con «Qué no se ha traducido» y el siguiente paso, que es siempre eqproxy config validate sobre la salida.

Qué se convierte

La tabla describe la forma equivalente en cada dialecto; el conversor la genera cuando reconoce la construcción y, cuando no, lo nombra en el informe. El if de nginx es el caso típico: no se traduce solo.

PiezaHAProxynginxEnvoyingress-nginxEQProxy
Ruta por prefijouse_backend … path_beglocation /prefijo/prefixpath Prefixpath_prefix + use_backend
Ruta exacta{ path /x }location = /xpathpath Exactpath
Hosthdr(host)server_namevirtual_hosts[].domainsIngress hosthost
Método{ method POST }if ($request_method …)cabecera :methodsnippetmethods
Canario por cookiecook(canary) -m str onmap $cookie_…regex sobre cookiecanary-by-cookiecookies
Canario por cabecerahdr(x-canary)map $http_x_canaryexact_matchcanary-by-headerheaders
Reescritura de prefijohttp-request set-pathrewrite … breakprefix_rewriterewrite-targetrewrite.path_prefix_rewrite
Redirecciónhttp-request redirectreturn 301redirectsnippetredirect
Respuesta localhttp-request returnreturn 200direct_responsesnippetdirect_response
Backend por defectodefault_backenddefault_serverdomains: ["*"]defaultBackendbackend del listener

Además: servidores con peso, marcados backup y con maxconn; checks de salud TCP y HTTP; retries; maxqueue; afinidad por cookie o por IP; slow_start; option forwardfor; TLS de cliente y de backend; errorfile/errorloc; CORS; rate limit; límites de cuerpo y cabeceras; timeouts; gzip; y map/geo como [maps.*].

Qué no se convierte

OrigenQueda fuera
nginxfastcgi_pass, uwsgi_pass, scgi_pass, memcached_pass; ficheros estáticos (root, alias, try_files, index); set y variables; if; proxy_method; proxy_buffering; limit_rate; ssl_ciphers; stream y ssl_preread
HAProxylua-load; stick-table como almacén; tcp-request/tcp-response; transparent y source; peers; external-check y agent-check; program, mailers, userlist
ingress-nginxconfiguration-snippet (nunca se ejecuta); ssl-passthrough; objetos que exigen vigilar el API server; servicios UDP
Envoyrecursos dinámicos (cds_config, xDS); filtros Lua; outlier detection y circuit breakers; udp_listener

Las rutas de certificado del origen no se copian: hay que ajustarlas a mano en el eqproxy.toml generado.

Ejemplo real: nginx antes, EQProxy después

Origen, extraído de docs/migration/nginx.conf (el vhost del storefront):

server {
    listen 8080;
    server_name shop.example.com;

    location = /healthz {
        return 200 "ok";
    }
    location /admin {
        if ($request_method = POST) { proxy_pass http://172.24.0.13:80; }
        proxy_pass http://172.24.0.11:80;
    }
}

Traducción, extraída de docs/migration/eqproxy.toml:

[[listener.web.rules]]
name = "healthz"
path = "/healthz"
[listener.web.rules.direct_response]
status = 200
body = "ok"

[[listener.web.rules]]
name = "admin-writes"
host = "shop.example.com"
path_prefix = "/admin"
methods = ["POST"]
use_backend = "admin"

[[listener.web.rules]]
name = "admin-reads"
host = "shop.example.com"
path_prefix = "/admin"
use_backend = "web"

El if ($request_method = POST) de nginx no tiene traducción directa: el conversor lo clasifica como directiva sin equivalente y remite a las reglas. La configuración de migración lo escribe como dos reglas ordenadas —primero la de POST, después la genérica— porque la primera coincidencia decide y no hay bloques condicionales.

El comando equivalente, con el informe al lado:

eqproxy config import --input nginx.conf --output eqproxy.toml --report report.md
eqproxy config validate --config eqproxy.toml

Una conversión limpia (código 0) no promete equivalencia funcional: promete que ninguna directiva se descartó en silencio. La equivalencia de enrutamiento se demuestra aparte, caso por caso, en la matriz de paridad.