
Servidor HTTP(S) de borda leve e proxy reverso com SSL automático, descoberta Docker/Consul, autenticação por rota, limitação de taxa e failover baseado em verificação de integridade.
<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 é um servidor HTTP(s) de borda simples / proxy reverso que suporta vários provedores (docker, estático, arquivo, catálogo consul). Um ou mais provedores fornecem informações sobre o servidor solicitado, a URL solicitada, a URL de destino e a URL de verificação de integridade. É distribuído como um único binário ou como um contêiner docker.
- Terminação SSL automática com <a href="https://letsencrypt.org/" rel="nofollow noopener noreferrer" target="_blank">Let's Encrypt</a>
- Suporte a certificados SSL fornecidos pelo usuário
- Regras de proxy simples, mas flexíveis
- Provedor de regras de proxy estático, via linha de comando
- Provedor de regras de proxy dinâmico, baseado em arquivo
- Provedor Docker com descoberta automática
- Provedor Consul Catalog com descoberta por tags de serviço
- Suporte a múltiplos hosts (virtuais)
- Compressão de tráfego opcional
- Controle de acesso opcional baseado em IP
- Autenticação básica por rota
- Limites de tamanho e timeouts definidos pelo usuário
- Distribuição em binário único
- Distribuição em contêiner Docker
- Servidor de assets estáticos integrado com modo opcional "SPA friendly"
- Suporte a regras de redirecionamento
- Limitador opcional para a atividade geral, bem como para a atividade do usuário
- Verificação de integridade em tempo real e fail-over/balanceamento de carga
- Servidor de gerenciamento com informações de rotas e métricas prometheus
- Suporte a plugins via RPC para implementar funcionalidades personalizadas
- Logging opcional com o Apache Log Format e relatórios simplificados no 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>
O servidor (host) pode ser definido como FQDN, ou seja, `s.example.com`, `*` (catch all) ou uma regex. A correspondência exata tem prioridade, portanto, se houver duas regras com servidores `example.com` e `example\.(com|org)`, a requisição para `example.com/some/url` corresponderá à primeira. A URL solicitada pode ser uma regex, por exemplo `^/api/(.*)`, e a URL de destino pode conter grupos correspondentes da regex, ou seja, `http://d.example.com:8080/$1`. Para o exemplo acima, `http://s.example.com/api/something?foo=bar` será encaminhado via proxy para `http://d.example.com:8080/something?foo=bar`.
Por conveniência, requisições com `/` no final e sem grupos de regex são expandidas para `/(.*)`, e os destinos nesses casos são expandidos para `/$1`. Ou seja, `/api/` -> `http://127.0.0.1/service` será traduzido para `^/api/(.*)` -> `http://127.0.0.1/service/$1`.
A substituição de host é suportada na URL de destino. Por exemplo, `/files/${host}` será substituído pelo nome do host correspondente. `$host` (sem chaves) também pode ser usado.
Tanto HTTP quanto HTTPS são suportados. Para HTTPS, certificado estático pode ser usado, bem como certificados ACME automatizados (Let's Encrypt). Um servidor de assets opcional pode ser usado para servir arquivos estáticos. Iniciar o reproxy requer pelo menos um provedor definido. O restante dos parâmetros é estritamente opcional e possui padrões sensatos.
Exemplos:
- com um provedor estático: `reproxy --static.enabled --static.rule="*,example.com/api/(.*),https://api.example.com/$1"`
- com descoberta automática do docker: `reproxy --docker.enabled --docker.auto`
- como um contêiner docker: `docker up -p 80:8080 umputun/reproxy --docker.enabled --docker.auto`
- com SSL automático: `docker up -p 80:8080 -p 443:8443 umputun/reproxy --docker.enabled --docker.auto --ssl.type=auto --ssl.fqdn=example.com`
## Instalação
O Reproxy é distribuído como um pequeno binário autocontido, bem como uma imagem docker. Tanto o binário quanto a imagem suportam múltiplas arquiteturas e múltiplos sistemas operacionais, incluindo linux_x86_64, linux_arm64, linux_arm, macos_x86_64, macos_arm64, windows_x86_64 e windows_arm. Também fornecemos pacotes deb e rpm para arm64 e x86.
- para uma distribuição binária, baixe o arquivo apropriado na [seção de releases](https://github.com/umputun/reproxy/releases)
- para usuários do Homebrew: `brew install umputun/apps/reproxy`
- container docker disponível no [Docker Hub](https://hub.docker.com/r/umputun/reproxy), bem como no [Github Container Registry](https://github.com/users/umputun/packages/container/reproxy/versions). Ou seja, `docker pull umputun/reproxy` ou `docker pull ghcr.io/umputun/reproxy`.
A versão estável mais recente tem a tag docker `:vX.Y.Z` (com o alias `:latest`) e o master atual tem a tag `:master`.
## Providers
Regras de proxy fornecidas por vários providers. Atualmente incluídos - `file`, `docker`, `static` e `consul-catalog`. Cada provider pode definir múltiplas regras de roteamento tanto para requisições proxiadas quanto para estáticos (assets). O usuário pode definir vários providers ao mesmo tempo.
_Veja exemplos de vários providers em [examples](https://github.com/umputun/reproxy/tree/master/examples)_
### Static provider
Este é o provider mais simples, que define todas as regras de mapeamento diretamente na linha de comando (ou ambiente). Múltiplas regras são suportadas. Cada regra é composta de 3 a 7 elementos separados por vírgula `server,sourceurl,destination[,ping-url[,forward-health-checks[,timeout[,throttle]]]]`. Por exemplo:
- `*,^/api/(.*),https://api.example.com/$1` - proxiar todas as requisições para qualquer host/server com prefixo `/api` para `https://api.example.com`
- `example.com,/foo/bar,https://api.example.com/zzz,https://api.example.com/ping` - proxiar todas as requisições para `example.com` e com url `/foo/bar` para `https://api.example.com/zzz` e ele consulta `https://api.example.com/ping` para o health check.
- `example.com,/foo/bar,https://api.example.com/zzz,https://api.example.com/ping,true` - o mesmo que acima, mas também encaminha requisições `/ping` e `/health` para o backend.
- `example.com,^/upload/(.*),https://api.example.com/$1,,,5m` - timeout de requisição por rota de 5 minutos (4º e 5º campos deixados vazios para pular ping-url e forward-health-checks).
- `example.com,^/login,https://api.example.com/login,,,,2` - throttle por rota de 2 req/seg por usuário (os campos posicionais anteriores são deixados vazios).
O 4º elemento define uma ping url opcional usada para relatório de saúde. O 5º elemento opcionalmente habilita o encaminhamento de requisições de health check para o backend (`true`, `yes`, `1`). Veja a seção [Health check](#ping-and-health-checks) para mais detalhes. O 6º elemento é um timeout de requisição por rota opcional (duração Go, por exemplo `5m`, `30s`); `0` ou vazio herda a configuração global `--timeout.write`. O 7º elemento é um limite opcional de req/seg por usuário por rota; `0` ou vazio herda `--throttle.user`. Campos posicionais vazios são permitidos (por exemplo, `,,` para os campos intermediários não utilizados).
### File provider
Este provider usa um arquivo yaml com regras de roteamento.
`reproxy --file.enabled --file.name=config.yml`
Exemplo 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 é um provedor dinâmico e a alteração do arquivo será aplicada automaticamente.
**Vários sites estáticos em domínios diferentes** podem ser servidos usando nomes de servidor como chaves com `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:** o campo `route` para regras de assets deve ser um prefixo de caminho (por exemplo, `/`, `/web/`), não uma regex. Padrões regex como `^/(.*)` não funcionarão com `assets: true` porque a correspondência de assets estáticos usa comparação de prefixo de caminho, não regex.
### Provedor Docker
O provedor Docker suporta descoberta totalmente automática (com `--docker.auto`) sem necessidade de configuração extra. Por padrão, ele redireciona todas as requisições como `http://<url>/<container name>/(.*)` para o IP interno do container fornecido e a porta exposta. Apenas containers ativos (em execução) serão detectados.
Esse padrão pode ser alterado com labels:
- `reproxy.server` - servidor (hostname) a corresponder. Também pode ser uma lista de servidores separados por vírgula.
- `reproxy.route` - rota de origem (location)
- `reproxy.dest` - caminho de destino. Nota: não é a url completa, mas apenas o caminho que será anexado ao ip:porta do container
- `reproxy.port` - porta de destino para o container descoberto
- `reproxy.ping` - caminho de ping para o container de destino.
- `reproxy.remote` - restringe o acesso à rota com uma lista de sub-redes ou ips separados por vírgula
- `reproxy.auth` - exige autenticação básica para a rota com pares `user:bcrypt_hash` separados por vírgula (gerados por `htpasswd -nbB`)
- `reproxy.assets` - define o mapeamento de assets como `web-root:location`, por exemplo `reproxy.assets=/web:/var/www`
- `reproxy.keep-host` - mantém o cabeçalho host como está (`yes`, `true`, `1`) ou substitui pelo host de destino (`no`, `false`, `0`)
- `reproxy.forward-health-checks` - encaminha requisições `/ping` e `/health` para o backend em vez de o reproxy tratá-las (`yes`, `true`, `1`). Útil quando o backend possui seus próprios endpoints de health check com respostas específicas da aplicação.
- `reproxy.timeout` - timeout de requisição por rota como duração Go (por exemplo, `5m`, `30s`). `0` ou não definido herda o `--timeout.write` global. Valores inválidos são ignorados com um aviso.
- `reproxy.throttle` - limite de req/seg por usuário por rota. `0` ou não definido herda `--throttle.user`. Valores inválidos ou negativos são ignorados com um aviso.
- `reproxy.enabled` - habilita (`yes`, `true`, `1`) ou desabilita (`no`, `false`, `0`) o container dos destinos do reproxy.
Obs.: sem `--docker.auto`, o container de destino precisa ter pelo menos uma das labels `reproxy.*` para ser considerado um destino potencial.
Com `--docker.auto`, todos os containers com porta exposta serão considerados destinos de roteamento. Há 3 formas de restringir isso:
- Excluir alguns containers explicitamente com `--docker.exclude`, ou seja, `--docker.exclude=c1 --docker.exclude=c2 ...`
- Permitir apenas uma rede docker específica com `--docker.network`
- Definir a label `reproxy.enabled=false` ou `reproxy.enabled=no` ou `reproxy.enabled=0`
Se nenhum `reproxy.route` for definido, a rota padrão é `^/<container_name>/(.*)`. Caso todas as origens proxy devam ter o mesmo padrão de prefixo, por exemplo `/api/(.*)`, o usuário pode definir o prefixo comum (neste caso `/api`) para todas as rotas baseadas em container. Isso pode ser feito com o parâmetro `--docker.prefix`.
O provedor Docker também permite definir múltiplos conjuntos de labels `reproxy.N.something` para corresponder a múltiplas rotas distintas no mesmo container. Isso é útil pois, em alguns casos, um único container pode expor múltiplos endpoints, por exemplo, API pública e alguma API de administração. Todas as labels acima podem ser usadas com "N-index", ou seja, `reproxy.1.server`, `reproxy.1.port` e assim por diante. N deve estar no intervalo de 0 a 9.
Este é um provedor dinâmico e qualquer mudança no status do container será aplicada automaticamente.
### Provedor Consul Catalog
Uso: `reproxy --consul-catalog.enabled`
O provedor Consul Catalog chama a API do Consul periodicamente (a cada segundo por padrão) para obter serviços que possuam alguma tag com o prefixo `reproxy.`. O usuário pode redefinir o intervalo de verificação com a flag de linha de comando `--consul-catalog.interval`, bem como o endereço do consul com a opção de linha de comando `--consul-catalog.address`. O endereço padrão é `http://127.0.0.1:8500`.
Por exemplo:
```
reproxy --consul-catalog.enabled --consul-catalog.address=http://192.168.1.100:8500 --consul-catalog.interval=10s
```
Por padrão, o provider define valores para cada serviço:
- enabled `false`
- server `*`
- route `^/(.*)`
- dest `http://<SERVICE_ADDRESS_FROM_CONSUL>/$1`
- ping `http://<SERVICE_ADDRESS_FROM_CONSUL>/ping`
Esse padrão pode ser alterado com tags:
- `reproxy.server` - server (hostname) a corresponder. Também pode ser uma lista de servidores separados por vírgula.
- `reproxy.route` - rota de origem (location)
- `reproxy.dest` - caminho de destino. Nota: não é a url completa, mas apenas o caminho que será anexado ao ip:port do serviço
- `reproxy.port` - porta de destino para o serviço descoberto
- `reproxy.remote` - restringe o acesso à rota com uma lista de sub-redes ou ips separados por vírgula
- `reproxy.auth` - exige autenticação básica para a rota com pares `user:bcrypt_hash` separados por vírgula (gerados por `htpasswd -nbB`)
- `reproxy.ping` - caminho de ping para o serviço de destino.
- `reproxy.forward-health-checks` - encaminha requisições `/ping` e `/health` para o backend (`true`, `yes`, `1`).
- `reproxy.timeout` - timeout de requisição por rota como uma duração Go (por exemplo, `5m`, `30s`). `0` ou não definido herda o `--timeout.write` global. Valores inválidos são ignorados com um aviso.
- `reproxy.throttle` - limite de req/seg por rota por usuário. `0` ou não definido herda `--throttle.user`. Valores inválidos ou negativos são ignorados com um aviso.
- `reproxy.enabled` - habilita (`yes`, `true`, `1`) ou desabilita (`qualquer valor diferente`) o serviço dos destinos do reproxy.
### Detalhes específicos do Compose
Caso as regras sejam definidas como parte do ambiente do docker compose, o destino com o grupo regex entrará em conflito com a sintaxe do compose. Ou seja, tentar usar `https://api.example.com/$1` no ambiente do compose falhará devido a um erro de sintaxe. A solução padrão aqui é "escapar" o sinal `$` substituindo-o por `$$`, ou seja, `https://api.example.com/$$1`. Essa substituição é suportada pelo docker compose e não tem nada a ver com o próprio reproxy. Outra forma é usar `@` em vez de `$`, o que é suportado no nível do reproxy, ou seja, `https://api.example.com/@1`_
## Suporte a SSL
O modo SSL (por padrão nenhum) pode ser definido como `auto` (certificados ACME/LE), `static` (certificado existente) ou `none`. Se `auto` estiver ativado, o certificado SSL será emitido automaticamente para todos os nomes de servidor descobertos. O usuário pode substituí-lo definindo valor(es) em `--ssl.fqdn`. Nos modos SSL `auto` e `static`, o Reproxy adicionará automaticamente os cabeçalhos `X-Forwarded-Proto` e `X-Forwarded-Port`. Esses cabeçalhos são úteis para serviços atrás do proxy saberem o protocolo original (http ou https) e o número da porta usados pelo cliente.
Ao usar ACME com providers de descoberta (docker, file, consul), os certificados SSL são obtidos automaticamente para servidores recém-descobertos sem exigir a reinicialização do reproxy.
### Desafios ACME
O Reproxy suporta dois tipos de desafios ACME para validação de certificados SSL:
1. **Desafio HTTP-01** (padrão): Valida a propriedade do domínio servindo um token em uma URL HTTP específica. Requer que a porta 80 esteja publicamente acessível.
2. **Desafio DNS-01**: Valida a propriedade do domínio criando registros DNS TXT. Este método:
- Não requer que a porta 80 esteja acessível
- Funciona com certificados wildcard
- Requer uma configuração de provider DNS suportado
#### Seleção de Desafio
O Reproxy determina automaticamente qual método de desafio usar com base na sua configuração:
- **HTTP-01** (padrão): Usado quando nenhum provider DNS está configurado
- **DNS-01**: Usado quando um provider DNS está configurado
Você não precisa selecionar explicitamente um tipo de desafio - basta configurar um provider DNS se quiser usar desafios DNS-01.
As verificações de propagação DNS expiram após 2 minutos por padrão. Aumente isso com `--ssl.dns.propagation-timeout=5m` para zonas que publicam registros de desafio lentamente. A opção `--ssl.dns.ttl` controla o TTL do registro e não altera o timeout de propagação.
#### Providers DNS Atualmente Suportados
O Reproxy atualmente inclui suporte para os seguintes providers 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`
Exemplo com o Cloudflare como provedor de DNS:
```
export CLOUDFLARE_API_TOKEN=your_api_token
reproxy --ssl.type=auto [email protected] --ssl.fqdn=example.com
```
O desafio DNS-01 é especialmente útil quando:
- Seu servidor não tem a porta 80 exposta publicamente
- Você precisa de certificados wildcard (por exemplo, *.example.com)
- Você está atrás de firewalls restritivos
## Headers
O Reproxy permite sanitizar (remover) cabeçalhos de entrada passando o parâmetro `--drop-header` (pode ser repetido). Este parâmetro pode ser útil para garantir que alguns dos cabeçalhos, definidos internamente pelos serviços, não possam ser definidos/falsificados pelo usuário final. Por exemplo, se alguns dos serviços, responsáveis pela autenticação, definem `X-Auth-User` e `X-Auth-Token`, provavelmente faz sentido remover esses cabeçalhos das requisições de entrada passando o parâmetro `--drop-header=X-Auth-User --drop-header=X-Auth-Token` ou via ambiente `DROP_HEADERS=X-Auth-User,X-Auth-Token`
A função oposta, definir cabeçalho(s) de saída, também é suportada. Pode ser útil em muitos casos, por exemplo, para impor algumas regras CORS personalizadas, cabeçalhos relacionados à segurança e assim por diante. Isso pode ser feito com o parâmetro `--header` (pode ser repetido) ou com a variável de ambiente `HEADER`. Por exemplo, é assim que pode ser feito com o 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 padrão, nenhum log de requisições é gerado. Isso pode ser ativado definindo `--logger.enabled`. O log (com rotação automática) usa o [Apache Combined Log Format](http://httpd.apache.org/docs/2.2/logs.html#combined)
O usuário também pode ativar o log em stdout com `--logger.stdout`. Isso não afetará o registro em arquivo mencionado acima, mas exibirá algumas informações mínimas sobre as requisições processadas, algo como isto:
```
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
Os usuários podem ativar o servidor de assets (desativado por padrão) para servir arquivos estáticos. Desde que `--assets.location` esteja definido, ele trata toda requisição não-proxied sob `assets.root` como uma requisição para arquivos estáticos. O servidor de assets pode ser usado sem quaisquer provedores de proxy; neste modo, o reproxy atua como um servidor web simples para o conteúdo estático. O servidor de assets também suporta o "modo spa" com `--assets.spa`, onde todas as requisições não encontradas são encaminhadas para `index.html`.
Além do servidor de assets comum, múltiplos servidores de assets personalizados são suportados. Cada provedor tem uma maneira diferente de definir tal regra estática, e alguns provedores podem não suportá-la de forma alguma. Por exemplo, múltiplos servidores de assets fazem sentido no provedor estático (linha de comando), no provedor de arquivos e até mesmo são úteis com provedores docker, porém fazem muito pouco sentido com o provedor de catálogo consul.
1. provedor estático - se o elemento de origem for prefixado por `assets:` ou `spa:`, ele será tratado como file-server. Por exemplo, `*,assets:/web,/var/www,` servirá todas as requisições `/web/*` com um servidor de arquivos sobre o diretório `/var/www`.
2. provedor de arquivos - definindo os campos opcionais `assets: true` ou `spa: true`. Nota: o campo `route` deve ser um prefixo de caminho (por exemplo, `/`, `/web/`), não um padrão regex.
3. provedor docker - `reproxy.assets=web-root:location`, ou seja, `reproxy.assets=/web:/var/www`. A mudança para o modo spa é feita definindo `reproxy.spa` como `yes` ou `true`
### Cache
O servidor de assets suporta controle de cache com o parâmetro `--assets.cache=<duration>`. A duração `0s` (padrão) desativa o controle de cache. Uma duração é uma sequência de números decimais, cada um com fração opcional e um sufixo de unidade, como "300ms", "1.5h" ou "2h45m". As unidades de tempo válidas são "ns", "us" (ou "µs"), "ms", "s", "m", "h" e "d".
Existem duas maneiras de definir a duração do cache:
1. Um único valor para todos os assets estáticos. Isso é tão simples quanto `--assets.cache=48h`.
2. Duração personalizada para diferentes tipos mime. Deve incluir duas partes - o valor padrão e os pares de mime:duração. Na linha de comando, isso se parece com múltiplas opções `--assets.cache`, ou seja, `--assets.cache=48h --assets.cache=text/html:24h --assets.cache=image/png:2h`. Os valores de ambiente devem ser separados por vírgula, ou seja, `ASSETS_CACHE=48h,text/html:24h,image/png:2h`
Uma página 404 (não encontrada) personalizada pode ser definida com o parâmetro `--assets.not-found=<path>`. O caminho deve ser relativo à raiz dos assets.
## Usando o reproxy como imagem base
Servir conteúdo puramente estático é um dos casos de uso populares. Normalmente isso é usado para o contêiner de frontend separado que fornece apenas a UI. Com o servidor de assets, tal contêiner é quase trivial de criar. Este é um exemplo do contêiner que serve [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"]
```
Tudo o que ele precisa é copiar os assets estáticos para algum local e passar esse local como `"--assets.location` para o entrypoint do reproxy.
## Modo compatível com SPA
Algumas aplicações SPA contam com o proxy para tratar o 404 em assets estáticos de uma forma especial, redirecionando-o para "/index.html". Isso é semelhante à diretiva `try_files $uri $uri/ …` do nginx e, aparentemente, essa funcionalidade é de certa forma importante para as aplicações web modernas.
Este modo está desativado por padrão e pode ser ativado definindo `--assets.spa` ou a variável de ambiente `ASSETS_SPA=true`.
## Redirecionamentos
Por padrão, o reproxy trata o destino como um local de proxy, ou seja, ele invoca uma chamada http internamente e retorna a resposta ao cliente. No entanto, ao prefixar a url de destino com `@code`, esse comportamento pode ser alterado para redirecionamentos permanentes (código de status 301) ou temporários (código de status 302). Ou seja, o destino definido como `@301 https://example.com/something` causará um redirecionamento http permanente para `Location: https://example.com/something`
códigos suportados:
- `@301`, `@perm` - redirecionamento permanente
- `@302`, `@temp`, `@tmp` - redirecionamento temporário
## Mais opções
- `--gzip` ativa a compressão gzip (ou deflate) para as respostas. A decisão é tomada por resposta, a partir de seus cabeçalhos finais:
- tipos de mídia que correspondem a `--gzip-exclude` são enviados como estão. O valor é uma lista separada por vírgulas de tipos exatos (`image/png`) ou prefixos (`audio/*`). O padrão ignora áudio, vídeo, imagens comprimidas (jpeg, png, gif, webp, avif), fontes woff e arquivos comuns. Uma lista personalizada substitui o padrão, e um valor vazio (`--gzip-exclude=`) desativa as exclusões.
- respostas parciais (`206`, ou qualquer resposta com `Content-Range`) nunca são comprimidas, para que as requisições `Range` continuem funcionando.
- o reproxy não recomprime respostas que já possuem `Content-Encoding`. O `Accept-Encoding` do cliente é encaminhado ao upstream, então um upstream que comprime por conta própria decide por suas respostas, e a lista de exclusão se aplica apenas à compressão feita pelo reproxy.
- uma resposta comprimida remove `Accept-Ranges` e o `Content-Length` original, e um `ETag` forte torna-se fraco (`W/"..."`), porque seus bytes diferem do original.
- `--max=N` permite definir o tamanho máximo da requisição (padrão 64k). Defini-lo como `0` desativa a verificação de tamanho.
- `--timeout.*` vários timeouts tanto para o servidor quanto para o transporte do proxy. Veja a seção `timeout` em [All Application Options](#all-application-options). Um valor zero ou negativo significa que não haverá timeout.
- `--insecure` desativa a verificação SSL no host de destino. Isso é útil para certificados autoassinados.
## Portas padrão
Para eliminar a necessidade de passar parâmetros/variáveis de ambiente personalizados, o `--listen` padrão é dinâmico e tenta ser razoável e útil para os casos típicos:
- Se algo for definido pelos usuários em `--listen`, toda a lógica abaixo é ignorada e o host:porta informado é usado diretamente.
- Se nada for definido pelos usuários em `--listen` e o reproxy for executado fora do contêiner docker, o padrão é `127.0.0.1:80` para o modo http (`ssl.type=none`) e `127.0.0.1:443` para o modo ssl (`ssl.type=auto` ou `ssl.type=static`).
- Se nada for definido pelos usuários em `--listen` e o reproxy for executado dentro do docker, o padrão é `0.0.0.0:8080` para o modo http, e `0.0.0.0:8443` para o modo ssl.
Outro padrão definido de forma dinâmica semelhante é `--ssl.http-port`. Para execução dentro do contêiner docker, ele é definido como `8080` e, fora dele, como `80`.
## Ping, verificações de integridade e fail-over
O reproxy fornece dois endpoints para essa finalidade:
- `/ping` responde com `pong` e indica que o reproxy está ativo e em execução
- `/health` retorna o status `200 OK` se todos os servidores de destino responderam à sua requisição de ping com `200` ou `417 Expectation Failed` se algum dos servidores respondeu com um código diferente de 200. Ele também retorna um corpo json com detalhes sobre os serviços aprovados/reprovados.
Além dos endpoints acima, o reproxy suporta verificações de integridade (health checks) ao vivo opcionais. Neste caso (se habilitado), cada destino é verificado periodicamente quanto à resposta de ping e as rotas de destino com falha são excluídas. É possível retornar múltiplos destinos idênticos do mesmo ou de vários provedores, e apenas o aprovado é escolhido. Se várias correspondências forem descobertas e aprovadas - a última é escolhida de acordo com a estratégia `lb-type` (por padrão, seleção aleatória).
Para ativar a verificação de integridade ao vivo, o usuário deve definir `--health-check.enabled` (ou a variável de ambiente `HEALTH_CHECK_ENABLED=true`). Para personalizar o intervalo de verificação, pode-se usar `--health-check.interval=`.
## API de Gerenciamento
Opcional, pode ser ativada com `--mgmt.enabled`. Expõe 2 endpoints em `mgmt.listen` (endereço:porta):
- `GET /routes` - lista de todas as rotas descobertas
- `GET /metrics` - retorna métricas do prometheus (`http_requests_total`, `response_status` e `http_response_time_seconds`)
Por padrão, `http_response_time_seconds` usa os caminhos brutos das requisições como rótulos, o que pode causar alta cardinalidade com URLs dinâmicas (por exemplo, `/api/users/123`, `/api/users/456`). Use `--mgmt.low-cardinality` para alternar para padrões de rota (por exemplo, `^/api/users/(.*)`), reduzindo significativamente a cardinalidade das métricas.
_veja também [examples/metrics](https://github.com/umputun/reproxy/tree/master/examples/metrics)_
## Relatório de erros
O Reproxy retorna o erro 502 (Bad Gateway) caso a requisição não corresponda a nenhuma das rotas e assets fornecidos. Caso ocorra algum erro interno inesperado, ele retorna 500. Por padrão, o reproxy renderiza a versão de texto mais simples do erro - "Server error". Definir `--error.enabled` ativa a mensagem de erro HTML padrão e, com `--error.template`, o usuário pode definir qualquer arquivo de template HTML personalizado para a renderização do erro. O template possui duas variáveis: `{{.ErrCode}}` e `{{.ErrMessage}}`. Por exemplo, este template `oh my! {{.ErrCode}} - {{.ErrMessage}}` será renderizado como `oh my! 502 - Bad Gateway`
## Limitação de taxa (Throttling)
O Reproxy permite definir um valor máximo de req/seg no nível do sistema para a atividade geral do sistema, bem como por usuário. Valores 0 (padrão) são tratados como ilimitados.
A atividade do usuário é limitada tanto para rotas correspondentes quanto para não correspondentes. Todas as rotas não correspondentes são consideradas como um "único grupo de destino" e recebem um limitador comum que é `rate*3`. Isso significa que, se 10 (req/seg) forem definidos com `--throttle.user=10`, o usuário final poderá realizar até 30 requisições por segundo, seja para assets estáticos ou rotas não correspondentes. Para rotas correspondentes, este limitador é mantido por destino (rota), ou seja, a requisição encaminhada para s1.example.com/api permitirá 10 r/s e a requisição encaminhada para s2.example.com permitirá outros 10 r/s.
### Timeout e throttle por rota
---
[Read more](https://github.com/umputun/reproxy)