
Servidor HTTP(S) de borde ligero y proxy inverso con SSL automático, descubrimiento Docker/Consul, autenticación por ruta, limitación de velocidad y conmutación por error basada en comprobaciones de salud.
<div align="center">
<img class="logo" src="https://raw.githubusercontent.com/umputun/reproxy/master/site/logo-bg.svg" width="355px" height="142px" alt="Reproxy | Simple Reverse Proxy"/>
</div>
Reproxy es un servidor HTTP(s) de borde / proxy inverso simple que admite varios proveedores (docker, estático, archivo, catálogo de consul). Uno o más proveedores suministran información sobre el servidor solicitado, la URL solicitada, la URL de destino y la URL de comprobación de estado. Se distribuye como un único binario o como un contenedor docker.
- Terminación SSL automática con <a href="https://letsencrypt.org/" rel="nofollow noopener noreferrer" target="_blank">Let's Encrypt</a>
- Compatibilidad con certificados SSL proporcionados por el usuario
- Reglas de proxy simples pero flexibles
- Proveedor de reglas de proxy estático, por línea de comandos
- Proveedor de reglas de proxy dinámico, basado en archivos
- Proveedor Docker con descubrimiento automático
- Proveedor Consul Catalog con descubrimiento por etiquetas de servicio
- Compatibilidad con múltiples hosts (virtuales)
- Compresión de tráfico opcional
- Control de acceso opcional basado en IP
- Autenticación básica por ruta
- Límites de tamaño y tiempos de espera definidos por el usuario
- Distribución como binario único
- Distribución como contenedor Docker
- Servidor de recursos estáticos integrado con modo opcional "compatible con SPA"
- Compatibilidad con reglas de redirección
- Limitador opcional para la actividad general así como para la actividad del usuario
- Comprobación de estado en vivo y fail-over/balanceo de carga
- Servidor de gestión con información de rutas y métricas de prometheus
- Compatibilidad con plugins vía RPC para implementar funcionalidad personalizada
- Registro opcional tanto con Apache Log Format como con informes simplificados en stdout.
---
<div align="center">
[](https://github.com/umputun/reproxy/actions/workflows/ci.yml) [](https://coveralls.io/github/umputun/reproxy?branch=master) [](https://goreportcard.com/report/github.com/umputun/reproxy) [](https://hub.docker.com/r/umputun/reproxy)
</div>
El servidor (host) se puede establecer como FQDN, es decir, `s.example.com`, `*` (comodín) o una regex. La coincidencia exacta tiene prioridad, por lo que si hay dos reglas con los servidores `example.com` y `example\.(com|org)`, la solicitud a `example.com/some/url` coincidirá con la primera. La URL solicitada puede ser una regex, por ejemplo `^/api/(.*)`, y la URL de destino puede tener grupos coincidentes de la regex, es decir, `http://d.example.com:8080/$1`. Para el ejemplo anterior, `http://s.example.com/api/something?foo=bar` se redirigirá a `http://d.example.com:8080/something?foo=bar`.
Por conveniencia, las solicitudes con la barra final `/` y sin grupos de regex se expanden a `/(.*)`, y los destinos en esos casos se expanden a `/$1`. Es decir, `/api/` -> `http://127.0.0.1/service` se traducirá a `^/api/(.*)` -> `http://127.0.0.1/service/$1`.
La sustitución de host es compatible con la URL de destino. Por ejemplo, `/files/${host}` se reemplazará con el nombre del host coincidente. También se puede usar `$host` (sin llaves).
Se admiten tanto HTTP como HTTPS. Para HTTPS, se puede usar un certificado estático así como certificados ACME automatizados (Let's Encrypt). Se puede usar un servidor de recursos opcional para servir archivos estáticos. Iniciar reproxy requiere al menos un proveedor definido. El resto de parámetros son estrictamente opcionales y tienen valores predeterminados razonables.
Ejemplos:
- con un proveedor estático: `reproxy --static.enabled --static.rule="*,example.com/api/(.*),https://api.example.com/$1"`
- con descubrimiento automático de docker: `reproxy --docker.enabled --docker.auto`
- como contenedor docker: `docker up -p 80:8080 umputun/reproxy --docker.enabled --docker.auto`
- con SSL automático: `docker up -p 80:8080 -p 443:8443 umputun/reproxy --docker.enabled --docker.auto --ssl.type=auto --ssl.fqdn=example.com`
## Instalación
Reproxy se distribuye como un pequeño binario autocontenido, así como una imagen de docker. Tanto el binario como la imagen soportan múltiples arquitecturas y múltiples sistemas operativos, incluyendo linux_x86_64, linux_arm64, linux_arm, macos_x86_64, macos_arm64, windows_x86_64 y windows_arm. También proporcionamos paquetes deb y rpm tanto para arm64 como para x86.
- para una distribución binaria, descargue el archivo adecuado en la [sección de releases](https://github.com/umputun/reproxy/releases)
- para usuarios de Homebrew: `brew install umputun/apps/reproxy`
- contenedor docker disponible en [Docker Hub](https://hub.docker.com/r/umputun/reproxy), así como en [Github Container Registry](https://github.com/users/umputun/packages/container/reproxy/versions). Es decir, `docker pull umputun/reproxy` o `docker pull ghcr.io/umputun/reproxy`.
La última versión estable tiene la etiqueta docker `:vX.Y.Z` (con el alias `:latest`) y el master actual tiene la etiqueta `:master`.
## Proveedores
Reglas de proxy suministradas por varios proveedores. Actualmente incluidos: `file`, `docker`, `static` y `consul-catalog`. Cada proveedor puede definir múltiples reglas de enrutamiento tanto para solicitudes proxied como para estáticos (assets). El usuario puede establecer múltiples proveedores al mismo tiempo.
_Consulte ejemplos de varios proveedores en [examples](https://github.com/umputun/reproxy/tree/master/examples)_
### Proveedor static
Este es el proveedor más simple, que define todas las reglas de mapeo directamente en la línea de comandos (o en el entorno). Se admiten múltiples reglas. Cada regla consta de 3 a 7 elementos separados por comas `server,sourceurl,destination[,ping-url[,forward-health-checks[,timeout[,throttle]]]]`. Por ejemplo:
- `*,^/api/(.*),https://api.example.com/$1` - redirige todas las solicitudes a cualquier host/servidor con el prefijo `/api` a `https://api.example.com`
- `example.com,/foo/bar,https://api.example.com/zzz,https://api.example.com/ping` - redirige todas las solicitudes a `example.com` y con la url `/foo/bar` a `https://api.example.com/zzz` y consulta `https://api.example.com/ping` para el health check.
- `example.com,/foo/bar,https://api.example.com/zzz,https://api.example.com/ping,true` - igual que el anterior pero también reenvía las solicitudes `/ping` y `/health` al backend.
- `example.com,^/upload/(.*),https://api.example.com/$1,,,5m` - timeout de solicitud por ruta de 5 minutos (los campos 4.º y 5.º se dejan vacíos para omitir ping-url y forward-health-checks).
- `example.com,^/login,https://api.example.com/login,,,,2` - throttle por ruta de 2 req/seg por usuario (los campos posicionales anteriores se dejan vacíos).
El 4.º elemento define una url de ping opcional utilizada para el reporte de salud. El 5.º elemento habilita opcionalmente el reenvío de solicitudes de health check al backend (`true`, `yes`, `1`). Consulte la sección [Health check](#ping-and-health-checks) para más detalles. El 6.º elemento es un timeout de solicitud opcional por ruta (duración de Go, p. ej. `5m`, `30s`); `0` o vacío hereda la configuración global `--timeout.write`. El 7.º elemento es un límite opcional de req/seg por usuario por ruta; `0` o vacío hereda `--throttle.user`. Se permiten campos posicionales vacíos (p. ej. `,,` para los campos intermedios no utilizados).
### Proveedor file
Este proveedor utiliza un archivo yaml con reglas de enrutamiento.
`reproxy --file.enabled --file.name=config.yml`
Ejemplo de `config.yml`:
```yaml
default: # the same as * (catch-all) server
- { route: "^/api/svc1/(.*)", dest: "http://127.0.0.1:8080/blah1/$1" }
- {
route: "/api/svc3/xyz",
dest: "http://127.0.0.3:8080/blah3/xyz",
ping: "http://127.0.0.3:8080/ping",
remote: "192.168.1.0/24, 127.0.0.1", # optional, restrict access to the route
forward-health-checks: true # optional, forward /ping and /health to backend
}
- {
route: "^/admin/(.*)",
dest: "http://127.0.0.4:8080/$1",
auth: "admin:$2y$05$..." # optional, per-route basic auth (htpasswd bcrypt format)
}
- {
route: "^/upload/(.*)",
dest: "http://127.0.0.5:8080/$1",
timeout: 5m # optional, per-route request timeout (Go duration). 0 or omitted inherits --timeout.write
}
- {
route: "^/login",
dest: "http://127.0.0.6:8080/login",
throttle: 2 # optional, per-route req/sec per user. 0 or omitted inherits --throttle.user
}
srv.example.com:
- { route: "^/api/svc2/(.*)", dest: "http://127.0.0.2:8080/blah2/$1/abc" }
- { route: "/web/", dest: "/var/www", "assets": true }
"*.files.example.com":
- { route: "^/files/(.*)", dest: "http://123.123.200.200:8080/$host/$1" }
```
Este es un proveedor dinámico y el cambio de archivo se aplicará automáticamente.
**Múltiples sitios estáticos en dominios diferentes** pueden servirse usando nombres de servidor como claves con `assets: true`:
```yaml
site-en.example.com:
- { route: "/", dest: "/var/www/en", "assets": true }
site-ru.example.com:
- { route: "/", dest: "/var/www/ru", "assets": true }
```
**Importante:** el campo `route` para las reglas de assets debe ser un prefijo de ruta (p. ej., `/`, `/web/`), no una regex. Los patrones regex como `^/(.*)` no funcionarán con `assets: true` porque la coincidencia de assets estáticos utiliza comparación por prefijo de ruta, no regex.
### Proveedor Docker
El proveedor Docker admite un descubrimiento totalmente automático (con `--docker.auto`) sin necesidad de configuración adicional. Por defecto, redirige todas las solicitudes como `http://<url>/<container name>/(.*)` a la IP interna del contenedor dado y al puerto expuesto. Solo se detectarán los contenedores activos (en ejecución).
Este comportamiento por defecto se puede cambiar con etiquetas:
- `reproxy.server` - servidor (nombre de host) con el que coincidir. También puede ser una lista de servidores separados por comas.
- `reproxy.route` - ruta de origen (ubicación)
- `reproxy.dest` - ruta de destino. Nota: no es la URL completa, sino solo la ruta que se añadirá a la ip:puerto del contenedor
- `reproxy.port` - puerto de destino para el contenedor descubierto
- `reproxy.ping` - ruta de ping para el contenedor de destino.
- `reproxy.remote` - restringe el acceso a la ruta con una lista de subredes o ips separadas por comas
- `reproxy.auth` - requiere autenticación básica para la ruta con pares `user:bcrypt_hash` separados por comas (generados por `htpasswd -nbB`)
- `reproxy.assets` - establece el mapeo de assets como `web-root:location`, por ejemplo `reproxy.assets=/web:/var/www`
- `reproxy.keep-host` - mantiene el encabezado host tal cual (`yes`, `true`, `1`) o lo reemplaza con el host de destino (`no`, `false`, `0`)
- `reproxy.forward-health-checks` - reenvía las solicitudes `/ping` y `/health` al backend en lugar de que reproxy las gestione (`yes`, `true`, `1`). Útil cuando el backend tiene sus propios endpoints de health check con respuestas específicas de la aplicación.
- `reproxy.timeout` - tiempo de espera de solicitud por ruta como duración de Go (p. ej. `5m`, `30s`). `0` o sin definir hereda el `--timeout.write` global. Los valores no válidos se ignoran con una advertencia.
- `reproxy.throttle` - límite de solicitudes por segundo por usuario y por ruta. `0` o sin definir hereda `--throttle.user`. Los valores no válidos o negativos se ignoran con una advertencia.
- `reproxy.enabled` - habilita (`yes`, `true`, `1`) o deshabilita (`no`, `false`, `0`) el contenedor como destino de reproxy.
Nota: sin `--docker.auto`, el contenedor de destino debe tener al menos una de las etiquetas `reproxy.*` para ser considerado como destino potencial.
Con `--docker.auto`, todos los contenedores con puerto expuesto se considerarán destinos de enrutamiento. Hay 3 formas de restringirlo:
- Excluir algunos contenedores explícitamente con `--docker.exclude`, es decir, `--docker.exclude=c1 --docker.exclude=c2 ...`
- Permitir solo una red docker en particular con `--docker.network`
- Establecer la etiqueta `reproxy.enabled=false` o `reproxy.enabled=no` o `reproxy.enabled=0`
Si no se define `reproxy.route`, la ruta por defecto es `^/<container_name>/(.*)`. En caso de que todo el origen proxificado deba tener el mismo patrón de prefijo, por ejemplo `/api/(.*)`, el usuario puede definir el prefijo común (en este caso `/api`) para todas las rutas basadas en contenedores. Esto se puede hacer con el parámetro `--docker.prefix`.
El proveedor Docker también permite definir múltiples conjuntos de etiquetas `reproxy.N.something` para hacer coincidir múltiples rutas distintas en el mismo contenedor. Esto es útil ya que en algunos casos un único contenedor puede exponer múltiples endpoints, por ejemplo, una API pública y alguna API de administración. Todas las etiquetas anteriores se pueden usar con "N-index", es decir, `reproxy.1.server`, `reproxy.1.port`, etc. N debe estar en el rango de 0 a 9.
Este es un proveedor dinámico y cualquier cambio en el estado del contenedor se aplicará automáticamente.
### Proveedor Consul Catalog
Uso: `reproxy --consul-catalog.enabled`
El proveedor Consul Catalog llama a la API de Consul periódicamente (cada segundo por defecto) para obtener los servicios que tienen alguna etiqueta con el prefijo `reproxy.`. El usuario puede redefinir el intervalo de comprobación con el flag de línea de comandos `--consul-catalog.interval`, así como la dirección de consul con la opción de línea de comandos `--consul-catalog.address`. La dirección por defecto es `http://127.0.0.1:8500`.
Por ejemplo:
```
reproxy --consul-catalog.enabled --consul-catalog.address=http://192.168.1.100:8500 --consul-catalog.interval=10s
```
Por defecto, el proveedor establece valores para cada servicio:
- enabled `false`
- server `*`
- route `^/(.*)`
- dest `http://<SERVICE_ADDRESS_FROM_CONSUL>/$1`
- ping `http://<SERVICE_ADDRESS_FROM_CONSUL>/ping`
Este valor por defecto se puede cambiar con etiquetas:
- `reproxy.server` - servidor (nombre de host) con el que coincidir. También puede ser una lista de servidores separados por comas.
- `reproxy.route` - ruta de origen (ubicación)
- `reproxy.dest` - ruta de destino. Nota: no es la URL completa, sino solo la ruta que se añadirá a la ip:puerto del servicio
- `reproxy.port` - puerto de destino para el servicio descubierto
- `reproxy.remote` - restringe el acceso a la ruta con una lista de subredes o ips separadas por comas
- `reproxy.auth` - requiere autenticación básica para la ruta con pares `user:bcrypt_hash` separados por comas (generados por `htpasswd -nbB`)
- `reproxy.ping` - ruta de ping para el servicio de destino.
- `reproxy.forward-health-checks` - reenvía las solicitudes `/ping` y `/health` al backend (`true`, `yes`, `1`).
- `reproxy.timeout` - tiempo de espera de solicitud por ruta como duración de Go (p. ej. `5m`, `30s`). `0` o sin establecer hereda el `--timeout.write` global. Los valores no válidos se ignoran con una advertencia.
- `reproxy.throttle` - límite de solicitudes/seg por usuario por ruta. `0` o sin establecer hereda `--throttle.user`. Los valores no válidos o negativos se ignoran con una advertencia.
- `reproxy.enabled` - habilita (`yes`, `true`, `1`) o deshabilita (`cualquier otro valor`) el servicio de los destinos de reproxy.
### Detalles específicos de Compose
En caso de que las reglas se establezcan como parte del entorno de docker compose, el destino con el grupo regex entrará en conflicto con la sintaxis de compose. Es decir, intentar usar `https://api.example.com/$1` en el entorno de compose fallará debido a un error de sintaxis. La solución estándar aquí es "escapar" el signo `$` reemplazándolo con `$$`, es decir, `https://api.example.com/$$1`. Esta sustitución es compatible con docker compose y no tiene nada que ver con reproxy en sí. Otra forma es usar `@` en lugar de `$`, lo cual es compatible a nivel de reproxy, es decir, `https://api.example.com/@1`_
## Soporte SSL
El modo SSL (por defecto ninguno) se puede establecer en `auto` (certificados ACME/LE), `static` (certificado existente) o `none`. Si se activa `auto`, el certificado SSL se emitirá automáticamente para todos los nombres de servidor descubiertos. El usuario puede anularlo estableciendo el/los valor(es) de `--ssl.fqdn`. En modo SSL `auto` y `static`, Reproxy añadirá automáticamente las cabeceras `X-Forwarded-Proto` y `X-Forwarded-Port`. Estas cabeceras son útiles para que los servicios detrás del proxy conozcan el protocolo original (http o https) y el número de puerto utilizado por el cliente.
Al usar ACME con proveedores de descubrimiento (docker, file, consul), los certificados SSL se obtienen automáticamente para los servidores recién descubiertos sin requerir un reinicio de reproxy.
### Desafíos ACME
Reproxy admite dos tipos de desafíos ACME para la validación de certificados SSL:
1. **Desafío HTTP-01** (predeterminado): valida la propiedad del dominio sirviendo un token en una URL HTTP específica. Requiere que el puerto 80 sea accesible públicamente.
2. **Desafío DNS-01**: valida la propiedad del dominio creando registros TXT de DNS. Este método:
- No requiere que el puerto 80 sea accesible
- Funciona con certificados comodín
- Requiere una configuración de proveedor DNS compatible
#### Selección de desafío
Reproxy determina automáticamente qué método de desafío usar según su configuración:
- **HTTP-01** (predeterminado): se usa cuando no hay ningún proveedor DNS configurado
- **DNS-01**: se usa cuando hay un proveedor DNS configurado
No necesita seleccionar explícitamente un tipo de desafío; simplemente configure un proveedor DNS si desea usar desafíos DNS-01.
Las comprobaciones de propagación de DNS agotan el tiempo de espera después de 2 minutos por defecto. Aumente esto con `--ssl.dns.propagation-timeout=5m` para zonas que publican registros de desafío lentamente. La opción `--ssl.dns.ttl` controla el TTL del registro y no cambia el tiempo de espera de propagación.
#### Proveedores DNS compatibles actualmente
Reproxy incluye actualmente soporte para los siguientes proveedores DNS:
- **Cloudflare**: `--ssl.dns.type=cloudflare --ssl.dns.cloudflare.api-token=TOKEN`
- **Route53 (AWS)**: `--ssl.dns.type=route53 --ssl.dns.route53.region=REGION --ssl.dns.route53.hosted-zone-id=ID`
- **Gandi**: `--ssl.dns.type=gandi --ssl.dns.gandi.bearer-token=TOKEN`
- **DigitalOcean**: `--ssl.dns.type=digitalocean --ssl.dns.digitalocean.api-token=TOKEN`
- **Hetzner**: `--ssl.dns.type=hetzner --ssl.dns.hetzner.api-token=TOKEN`
- **Linode**: `--ssl.dns.type=linode --ssl.dns.linode.api-token=TOKEN`
- **GoDaddy**: `--ssl.dns.type=godaddy --ssl.dns.godaddy.api-token=TOKEN`
- **Namecheap**: `--ssl.dns.type=namecheap --ssl.dns.namecheap.api-key=KEY --ssl.dns.namecheap.user=USER`
- **Scaleway**: `--ssl.dns.type=scaleway --ssl.dns.scaleway.secret-key=KEY --ssl.dns.scaleway.organization-id=ID`
- **Porkbun**: `--ssl.dns.type=porkbun --ssl.dns.porkbun.api-key=KEY --ssl.dns.porkbun.api-secret-key=SECRET`
- **DNSimple**: `--ssl.dns.type=dnsimple --ssl.dns.dnsimple.api-access-token=TOKEN --ssl.dns.dnsimple.account-id=ID`
- **DuckDNS**: `--ssl.dns.type=duckdns --ssl.dns.duckdns.api-token=TOKEN`
Ejemplo con Cloudflare como proveedor de DNS:
```
export CLOUDFLARE_API_TOKEN=your_api_token
reproxy --ssl.type=auto [email protected] --ssl.fqdn=example.com
```
El desafío DNS-01 es especialmente útil cuando:
- Tu servidor no tiene el puerto 80 expuesto públicamente
- Necesitas certificados comodín (por ejemplo, *.example.com)
- Estás detrás de firewalls restrictivos
## Encabezados
Reproxy permite sanear (eliminar) los encabezados entrantes pasando el parámetro `--drop-header` (se puede repetir). Este parámetro puede ser útil para asegurarse de que algunos de los encabezados, establecidos internamente por los servicios, no puedan ser establecidos/falsificados por el usuario final. Por ejemplo, si algunos de los servicios, responsables de la autenticación, establecen `X-Auth-User` y `X-Auth-Token`, es probable que tenga sentido eliminar esos encabezados de las solicitudes entrantes pasando el parámetro `--drop-header=X-Auth-User --drop-header=X-Auth-Token` o mediante la variable de entorno `DROP_HEADERS=X-Auth-User,X-Auth-Token`
La función opuesta, establecer encabezado(s) salientes, también es compatible. Puede ser útil en muchos casos, por ejemplo, para imponer algunas reglas CORS personalizadas, encabezados relacionados con la seguridad, etc. Esto se puede hacer con el parámetro `--header` (se puede repetir) o con la variable de entorno `HEADER`. Por ejemplo, así es como se puede hacer con docker compose:
```yaml
environment:
- HEADER=
X-Frame-Options:SAMEORIGIN,
X-XSS-Protection:1; mode=block;,
Content-Security-Policy:default-src 'self'; style-src 'self' 'unsafe-inline';
```
## Registro
Por defecto no se genera ningún registro de solicitudes. Esto se puede activar configurando `--logger.enabled`. El registro (con rotación automática) tiene [Apache Combined Log Format](http://httpd.apache.org/docs/2.2/logs.html#combined)
El usuario también puede activar el registro en stdout con `--logger.stdout`. No afectará al registro en archivo mencionado anteriormente, pero mostrará información mínima sobre las solicitudes procesadas, algo como esto:
```
2021/04/16 01:17:25.601 [INFO] GET - /echo/image.png - xxx.xxx.xxx.xxx - 200 (155400) - 371.661251ms
2021/04/16 01:18:18.959 [INFO] GET - /api/v1/params - xxx.xxx.xxx.xxx - 200 (74) - 1.217669m
```
## Servidor de assets
Los usuarios pueden activar el servidor de assets (desactivado por defecto) para servir archivos estáticos. Siempre que `--assets.location` esté configurado, trata cada solicitud no proxyada bajo `assets.root` como una solicitud de archivos estáticos. El servidor de assets se puede usar sin ningún proveedor de proxy; en este modo, reproxy actúa como un servidor web simple para el contenido estático. El servidor de assets también admite el "modo spa" con `--assets.spa`, donde todas las solicitudes no encontradas se reenvían a `index.html`.
Además del servidor de assets común, se admiten múltiples servidores de assets personalizados. Cada proveedor tiene una forma diferente de definir dicha regla estática, y algunos proveedores pueden no admitirla en absoluto. Por ejemplo, múltiples servidores de assets tienen sentido en el proveedor estático (línea de comandos), el proveedor de archivos e incluso son útiles con los proveedores de docker; sin embargo, tienen muy poco sentido con el proveedor de catálogo de consul.
1. proveedor estático - si el elemento de origen tiene el prefijo `assets:` o `spa:`, se tratará como servidor de archivos. Por ejemplo, `*,assets:/web,/var/www,` servirá todas las solicitudes `/web/*` con un servidor de archivos sobre el directorio `/var/www`.
2. proveedor de archivos - estableciendo los campos opcionales `assets: true` o `spa: true`. Nota: el campo `route` debe ser un prefijo de ruta (p. ej., `/`, `/web/`), no un patrón regex.
3. proveedor de docker - `reproxy.assets=web-root:location`, es decir, `reproxy.assets=/web:/var/www`. El cambio al modo spa se realiza estableciendo `reproxy.spa` en `yes` o `true`.
### Almacenamiento en caché
El servidor de assets admite el control de caché con el parámetro `--assets.cache=<duration>`. Una duración de `0s` (por defecto) desactiva el control de caché. Una duración es una secuencia de números decimales, cada uno con una fracción opcional y un sufijo de unidad, como "300ms", "1.5h" o "2h45m". Las unidades de tiempo válidas son "ns", "us" (o "µs"), "ms", "s", "m", "h" y "d".
Hay dos formas de establecer la duración de la caché:
1. Un único valor para todos los assets estáticos. Esto es tan simple como `--assets.cache=48h`.
2. Duración personalizada para diferentes tipos mime. Debe incluir dos partes: el valor predeterminado y los pares mime:duración. En la línea de comandos esto se ve como múltiples opciones `--assets.cache`, es decir, `--assets.cache=48h --assets.cache=text/html:24h --assets.cache=image/png:2h`. Los valores de entorno deben estar separados por comas, es decir, `ASSETS_CACHE=48h,text/html:24h,image/png:2h`
Se puede establecer una página 404 personalizada (no encontrada) con el parámetro `--assets.not-found=<path>`. La ruta debe ser relativa a la raíz de assets.
## Uso de reproxy como imagen base
Servir contenido puramente estático es uno de los casos de uso populares. Normalmente se usa para el contenedor frontend separado que proporciona solo la interfaz de usuario. Con el servidor de assets, crear un contenedor así es casi trivial. Este es un ejemplo del contenedor que sirve [reproxy.io](http://reproxy.io)
```docker
FROM node:22-alpine as build
WORKDIR /build
COPY site/ /build
COPY README.md /build/src/index.md
RUN yarn --frozen-lockfile
RUN yarn build
RUN ls -la /build/public
FROM ghcr.io/umputun/reproxy
COPY --from=build /build/public /srv/site
EXPOSE 8080
USER app
ENTRYPOINT ["/srv/reproxy", "--assets.location=/srv/site"]
```
Todo lo que necesita es copiar los recursos estáticos a alguna ubicación y pasar esta ubicación como `"--assets.location` al punto de entrada de reproxy.
## Modo compatible con SPA
Algunas aplicaciones SPA cuentan con que el proxy maneje el 404 en un recurso estático de una manera especial, redirigiéndolo a "/index.html". Esto es similar a la directiva `try_files $uri $uri/ …` de nginx y, aparentemente, esta funcionalidad es algo importante para las aplicaciones web modernas.
Este modo está desactivado por defecto y se puede activar estableciendo `--assets.spa` o la variable de entorno `ASSETS_SPA=true`.
## Redirecciones
Por defecto, reproxy trata el destino como una ubicación de proxy, es decir, invoca una llamada http internamente y devuelve la respuesta al cliente. Sin embargo, al prefijar la url de destino con `@code` este comportamiento puede cambiarse a redirecciones permanentes (código de estado 301) o temporales (código de estado 302). Es decir, un destino establecido en `@301 https://example.com/something` provocará una redirección http permanente a `Location: https://example.com/something`
códigos admitidos:
- `@301`, `@perm` - redirección permanente
- `@302`, `@temp`, `@tmp` - redirección temporal
## Más opciones
- `--gzip` habilita la compresión gzip (o deflate) para las respuestas. La decisión se toma por respuesta, a partir de sus encabezados finales:
- los tipos de medio que coinciden con `--gzip-exclude` se envían tal cual. El valor es una lista separada por comas de tipos exactos (`image/png`) o prefijos (`audio/*`). El valor predeterminado omite audio, video, imágenes comprimidas (jpeg, png, gif, webp, avif), fuentes woff y archivos comprimidos comunes. Una lista personalizada reemplaza la predeterminada, y un valor vacío (`--gzip-exclude=`) desactiva las exclusiones.
- las respuestas parciales (`206`, o cualquier respuesta con `Content-Range`) nunca se comprimen, por lo que las solicitudes `Range` siguen funcionando.
- reproxy no recomprime las respuestas que ya llevan `Content-Encoding`. El `Accept-Encoding` del cliente se reenvía al upstream, por lo que un upstream que comprime por su cuenta decide sobre sus respuestas, y la lista de exclusión se aplica solo a la compresión realizada por reproxy.
- una respuesta comprimida elimina `Accept-Ranges` y el `Content-Length` original, y un `ETag` fuerte se vuelve débil (`W/"..."`), porque sus bytes difieren del original.
- `--max=N` permite establecer el tamaño máximo de la solicitud (por defecto 64k). Establecerlo en `0` desactiva la comprobación de tamaño.
- `--timeout.*` varios tiempos de espera tanto para el servidor como para el transporte del proxy. Consulte la sección `timeout` en [All Application Options](#all-application-options). Un valor cero o negativo significa que no habrá tiempo de espera.
- `--insecure` desactiva la verificación SSL en el host de destino. Esto es útil para los certificados autofirmados.
## Puertos predeterminados
Con el fin de eliminar la necesidad de pasar parámetros/variables de entorno personalizados, el `--listen` predeterminado es dinámico e intenta ser razonable y útil para los casos típicos:
- Si el usuario establece algo en `--listen`, toda la lógica siguiente se ignora y el host:puerto proporcionado se usa directamente.
- Si el usuario no establece nada en `--listen` y reproxy se ejecuta fuera del contenedor docker, el valor predeterminado es `127.0.0.1:80` para el modo http (`ssl.type=none`) y `127.0.0.1:443` para el modo ssl (`ssl.type=auto` o `ssl.type=static`).
- Si el usuario no establece nada en `--listen` y reproxy se ejecuta dentro de docker, el valor predeterminado es `0.0.0.0:8080` para el modo http, y `0.0.0.0:8443` para el modo ssl.
Otro valor predeterminado establecido de forma dinámica similar es `--ssl.http-port`. Para ejecución dentro del contenedor docker se establece en `8080` y sin él en `80`.
## Ping, comprobaciones de estado y fail-over
reproxy proporciona dos endpoints para este propósito:
- `/ping` responde con `pong` e indica que reproxy está en funcionamiento
- `/health` devuelve el estado `200 OK` si todos los servidores de destino respondieron a su solicitud de ping con `200` o `417 Expectation Failed` si alguno de los servidores respondió con un código distinto de 200. También devuelve un cuerpo json con detalles sobre los servicios aprobados/fallidos.
Además de los endpoints anteriores, reproxy admite comprobaciones de estado en vivo opcionales. En este caso (si está habilitado), cada destino se comprueba periódicamente en busca de respuesta a ping y se excluyen las rutas de destino fallidas. Es posible que se devuelvan múltiples destinos idénticos desde el mismo o distintos proveedores, y solo se elige el que pasa. Si se descubren y pasan numerosas coincidencias, se elige la última según la estrategia `lb-type` (por defecto, selección aleatoria).
Para activar la comprobación de estado en vivo, el usuario debe establecer `--health-check.enabled` (o la variable de entorno `HEALTH_CHECK_ENABLED=true`). Para personalizar el intervalo de comprobación se puede usar `--health-check.interval=`.
## API de gestión
Opcional, se puede activar con `--mgmt.enabled`. Expone 2 endpoints en `mgmt.listen` (dirección:puerto):
- `GET /routes` - lista de todas las rutas descubiertas
- `GET /metrics` - devuelve métricas de prometheus (`http_requests_total`, `response_status` y `http_response_time_seconds`)
Por defecto, `http_response_time_seconds` usa las rutas de solicitud sin procesar como etiquetas, lo que puede provocar una alta cardinalidad con URL dinámicas (p. ej., `/api/users/123`, `/api/users/456`). Use `--mgmt.low-cardinality` para cambiar a patrones de ruta (p. ej., `^/api/users/(.*)`) en su lugar, reduciendo significativamente la cardinalidad de las métricas.
_ver también [examples/metrics](https://github.com/umputun/reproxy/tree/master/examples/metrics)_
## Informe de errores
Reproxy devuelve un error 502 (Bad Gateway) en caso de que la solicitud no coincida con ninguna de las rutas y assets proporcionados. En caso de que ocurra algún error interno inesperado, devuelve 500. Por defecto, reproxy muestra la versión de texto más simple del error: "Server error". Establecer `--error.enabled` activa el mensaje de error HTML predeterminado y con `--error.template` el usuario puede establecer cualquier archivo de plantilla HTML personalizado para la representación del error. La plantilla tiene dos variables: `{{.ErrCode}}` y `{{.ErrMessage}}`. Por ejemplo, esta plantilla `oh my! {{.ErrCode}} - {{.ErrMessage}}` se representará como `oh my! 502 - Bad Gateway`
## Limitación de velocidad
Reproxy permite definir un valor máximo de solicitudes por segundo a nivel de sistema para la actividad general del sistema, así como por usuario. Los valores 0 (predeterminados) se tratan como ilimitados.
---
[Read more](https://github.com/umputun/reproxy)