Voltar às atualizações
New releaseAug 20, 2026

reproxy v1.7.1

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.

Compartilhar
Reproxy | Proxy Reverso Simples

Reproxy é um servidor HTTP(s) de borda / proxy reverso simples que suporta vários provedores (docker, estático, arquivo, catálogo consul). Um ou mais provedores fornecem informações sobre o servidor solicitado, URL solicitada, URL de destino e URL de verificação de integridade. Ele é distribuído como um único binário ou como um contêiner docker.

  • Terminação SSL automática com Let's Encrypt
  • 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 baseado em IP opcional
  • Autenticação básica por rota
  • Limites de tamanho e timeouts definidos pelo usuário
  • Distribuição em único binário
  • Distribuição em contêiner Docker
  • Servidor de assets estáticos integrado com modo "SPA friendly" opcional
  • Suporte a regras de redirecionamento
  • Limitador opcional para atividade geral e por usuário
  • Verificação de integridade ao vivo 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
  • Log opcional tanto no formato Apache Log Format quanto relatórios simplificados no stdout.

build Coverage Status Go Report Card Docker Hub

O servidor (host) pode ser definido como FQDN, ex: s.example.com, * (captura todos) ou uma regex. A correspondência exata tem prioridade, portanto, se houver duas regras com servidores example.com e example\.(com|org), uma 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 ter grupos correspondentes por regex, ex: http://d.example.com:8080/$1. Para o exemplo acima, http://s.example.com/api/something?foo=bar será proxyada para http://d.example.com:8080/something?foo=bar.

Por conveniência, requisições com a barra / final e sem grupos de regex são expandidas para /(.*), e destinos nesses casos são expandidos para /$1. Ex: /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, um 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 que pelo menos um provedor seja definido. O restante dos parâmetros são estritamente opcionais e possuem 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

Reproxy é distribuído como um pequeno binário independente, 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.

A versão estável mais recente possui a tag docker :vX.Y.Z (com alias :latest) e o master atual tem a tag :master.

Provedores

As regras de proxy são fornecidas por vários provedores. Atualmente incluídos - file, docker, static e consul-catalog. Cada provedor pode definir múltiplas regras de roteamento tanto para requisições proxyadas quanto para estáticos (assets). O usuário pode configurar vários provedores ao mesmo tempo.

Veja exemplos de vários provedores em examples

Provedor estático

Este é o provedor mais simples, definindo todas as regras de mapeamento diretamente na linha de comando (ou ambiente). Múltiplas regras são suportadas. Cada regra possui de 3 a 7 elementos separados por vírgula servidor,urlorigem,destino[,url-ping[,encaminhar-verificacoes-saude[,timeout[,throttle]]]]. Por exemplo:

  • *,^/api/(.*),https://api.example.com/$1 - proxy todas as requisições para qualquer host/servidor com prefixo /api para https://api.example.com
  • example.com,/foo/bar,https://api.example.com/zzz,https://api.example.com/ping - proxy todas as requisições para example.com com a URL /foo/bar para https://api.example.com/zzz e usa https://api.example.com/ping para a verificação de integridade.
  • example.com,/foo/bar,https://api.example.com/zzz,https://api.example.com/ping,true - igual ao 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 ignorar url-ping e encaminhar-verificacoes-saude).
  • example.com,^/login,https://api.example.com/login,,,,2 - throttle por rota de 2 req/s por usuário (campos posicionais anteriores deixados vazios).

O 4º elemento define uma URL de ping opcional usada para relatórios de integridade. O 5º elemento habilita opcionalmente o encaminhamento de requisições de verificação de integridade para o backend (true, yes, 1). Consulte a seção Health check para mais detalhes. O 6º elemento é um timeout de requisição por rota opcional (duração Go, ex: 5m, 30s); 0 ou vazio herda a configuração global --timeout.write. O 7º elemento é um limite opcional de req/s por usuário por rota; 0 ou vazio herda --throttle.user. Campos posicionais vazios são permitidos (ex: ,, para os campos intermediários não utilizados).

Provedor de arquivo

Este provedor 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

Este é um provedor dinâmico e a alteração de arquivo será aplicada automaticamente. **Múltiplos 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 (ex.: /, /web/), não uma regex. Padrões de 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, redireciona todas as requisições como http://<url>/<nome do container>/(.*) para o IP interno do container dado 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) para correspondência. Também pode ser uma lista de servidores separados por vírgula.
  • reproxy.route - rota de origem (localização)
  • reproxy.dest - caminho de destino. Nota: não é uma URL completa, 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 - restringir acesso à rota com uma lista de sub-redes ou IPs separados por vírgula
  • reproxy.auth - exigir autenticação básica para a rota com pares user:bcrypt_hash separados por vírgula (gerados por htpasswd -nbB)
  • reproxy.assets - definir mapeamento de assets como web-root:localização, por exemplo reproxy.assets=/web:/var/www
  • reproxy.keep-host - manter o cabeçalho Host como está (yes, true, 1) ou substituir pelo host de destino (no, false, 0)
  • reproxy.forward-health-checks - encaminhar requisições /ping e /health para o backend em vez de o reproxy tratá-las (yes, true, 1). Útil quando o backend tem seus próprios endpoints de health check com respostas específicas da aplicação.
  • reproxy.timeout - tempo limite de requisição por rota como duração Go (ex.: 5m, 30s). 0 ou não definido herda o global --timeout.write. 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 - habilitar (yes, true, 1) ou desabilitar (no, false, 0) container dos destinos do reproxy.

Obs.: sem --docker.auto, o container de destino deve ter pelo menos uma das labels reproxy.* para ser considerado como destino potencial.

Com --docker.auto, todos os containers com porta exposta serão considerados como destinos de roteamento. Existem 3 maneiras de restringir:

  • Excluir alguns containers explicitamente com --docker.exclude, ex.: --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 é ^/<nome_do_container>/(.*). Caso todos os sources proxy devem 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 containers. 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 várias rotas distintas no mesmo container. Isso é útil, pois em alguns casos um único container pode expor vários endpoints, por exemplo, API pública e uma API de administração. Todas as labels acima podem ser usadas com "índice-N", ex.: 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 alteração 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 possuem qualquer tag com 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 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 provedor define valores para cada serviço:
- enabled `false`
- server `*`
- route `^/(.*)`
- dest `http://<SERVICE_ADDRESS_FROM_CONSUL>/$1`
- ping `http://<SERVICE_ADDRESS_FROM_CONSUL>/ping`

Este padrão pode ser alterado com tags:

- `reproxy.server` - servidor (hostname) para correspondência. Além disso, pode ser uma lista de servidores separados por vírgula.
- `reproxy.route` - rota de origem (localização)
- `reproxy.dest` - caminho de destino. Nota: não é uma URL completa, apenas o caminho que será anexado ao ip:porta do serviço
- `reproxy.port` - porta de destino para o serviço descoberto
- `reproxy.remote` - restringir o acesso à rota com uma lista de sub-redes ou IPs separados por vírgula
- `reproxy.auth` - exigir autenticação básica para a rota com pares `user:bcrypt_hash` separados por vírgula (gerado por `htpasswd -nbB`)
- `reproxy.ping` - caminho de ping para o serviço de destino.
- `reproxy.forward-health-checks` - encaminhar requisições `/ping` e `/health` para o backend (`true`, `yes`, `1`).
- `reproxy.timeout` - tempo limite por rota para requisições como duração Go (ex. `5m`, `30s`). `0` ou não definido herda o global `--timeout.write`. 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` - ativar (`yes`, `true`, `1`) ou desativar (`qualquer valor diferente`) o serviço dos destinos do reproxy.

### Detalhes específicos do Compose

Caso as regras sejam definidas como parte de um ambiente docker compose, o destino com o grupo regex entrará em conflito com a sintaxe do compose. Isto é, a tentativa de usar `https://api.example.com/$1` no ambiente 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`. Esta substituição é suportada pelo docker compose e não tem relação com o reproxy em si. Outra maneira é usar `@` em vez de `$`, que é suportado no nível do reproxy, ou seja, `https://api.example.com/@1`_

## Suporte 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 servidores descobertos. O usuário pode substituir definindo o(s) valor(es) de `--ssl.fqdn`. No modo 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 provedores de descoberta (docker, file, consul), certificados SSL são obtidos automaticamente para servidores recém-descobertos sem exigir 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 seja acessível publicamente.

2. **Desafio DNS-01**: Valida a propriedade do domínio criando registros DNS TXT. Este método:
   - Não requer que a porta 80 seja acessível
   - Funciona com certificados curinga
   - Requer configuração de um provedor 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 provedor DNS está configurado
- **DNS-01**: Usado quando um provedor DNS está configurado

Você não precisa selecionar explicitamente o tipo de desafio - basta configurar um provedor DNS se quiser usar desafios DNS-01.

#### Provedores DNS Atualmente Suportados

Atualmente, o Reproxy inclui suporte para os seguintes provedores 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 Cloudflare como provedor 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 curinga (ex.: *.example.com)
  • Você está atrás de firewalls restritivos

Cabeçalhos

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 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, aplicar 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 env 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';

## Logging

Por padrão, nenhum log de requisição é gerado. Isso pode ser ativado definindo `--logger.enabled`. O log (com rotação automática) possui o [Formato de Log Combinado do Apache](http://httpd.apache.org/docs/2.2/logs.html#combined)

O usuário também pode ativar o log no stdout com `--logger.stdout`. Isso não afetará o log em arquivo mencionado acima, mas exibirá algumas informações mínimas sobre requisições processadas, algo como:```
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 Ativos

Os utilizadores podem ativar o servidor de ativos (desativado por defeito) para servir ficheiros estáticos. Enquanto --assets.location estiver definido, trata cada pedido não-proxied sob assets.root como um pedido de ficheiros estáticos. O servidor de ativos pode ser usado sem qualquer fornecedor de proxy; neste modo, o reproxy atua como um simples servidor web para conteúdo estático. O servidor de ativos também suporta "modo spa" com --assets.spa, onde todos os pedidos não encontrados são encaminhados para index.html.

Além do servidor de ativos comum, são suportados múltiplos servidores de ativos personalizados. Cada fornecedor tem uma maneira diferente de definir tal regra estática, e alguns fornecedores podem nem suportá-la. Por exemplo, múltiplos servidores de ativos fazem sentido no fornecedor estático (linha de comando), fornecedor de ficheiros, e até úteis com fornecedores docker, no entanto faz muito pouco sentido com o fornecedor de catálogo consul.

  1. Fornecedor estático - se o elemento de origem for prefixado por assets: ou spa:, será tratado como servidor de ficheiros. Por exemplo *,assets:/web,/var/www, servirá todos os pedidos /web/* com um servidor de ficheiros sobre o diretório /var/www.
  2. Fornecedor de ficheiros - definindo campos opcionais assets: true ou spa: true. Nota: o campo route deve ser um prefixo de caminho (ex.: /, /web/), não um padrão regex.
  3. Fornecedor docker - reproxy.assets=web-root:location, i.e. reproxy.assets=/web:/var/www. A mudança para modo spa é feita definindo reproxy.spa para yes ou true

Cache

O servidor de ativos suporta controlo de cache com o parâmetro --assets.cache=<duração>. A duração 0s (padrão) desativa o controlo 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". Unidades de tempo válidas são "ns", "us" (ou "µs"), "ms", "s", "m", "h" e "d".

Existem duas formas de definir a duração da cache:

  1. Um único valor para todos os ativos estáticos. Isto é tão simples como --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, isto aparece como múltiplas opções --assets.cache, i.e. --assets.cache=48h --assets.cache=text/html:24h --assets.cache=image/png:2h. Os valores de ambiente devem ser separados por vírgulas, i.e. ASSETS_CACHE=48h,text/html:24h,image/png:2h

A página personalizada 404 (não encontrado) pode ser definida com o parâmetro --assets.not-found=<caminho>. O caminho deve ser relativo à raiz dos ativos.

Usar reproxy como imagem base

Servir conteúdo puramente estático é um dos casos de uso populares. Normalmente, isto é usado para o contentor frontend separado que fornece apenas UI. Com o servidor de ativos, tal contentor é quase trivial de fazer. Este é um exemplo do contentor que serve 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 precisa é copiar os ativos estáticos para algum local e passar esse local como `"--assets.location` para o ponto de entrada do reproxy.

## Modo SPA-friendly

Algumas aplicações SPA contam com o proxy para tratar 404 em ativos estáticos de uma maneira especial, redirecionando para "/index.html". Isso é semelhante à diretiva `try_files $uri $uri/ …` do nginx e, aparentemente, essa funcionalidade é um tanto importante para aplicações web modernas.

Este modo está desligado 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 faz uma chamada http internamente e retorna a resposta de volta ao cliente. No entanto, prefixando 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, 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 para respostas.
- `--max=N`  permite definir o tamanho máximo da requisição (padrão 64k). Definir como `0` desativa a verificação de tamanho.
- `--timeout.*` vários timeouts para o servidor e transporte de proxy. Veja a seção `timeout` em [Todas as Opções da Aplicação](#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/ambiente personalizados, o padrão `--listen` é dinâmico e tenta ser razoável e útil para os casos típicos:

- Se o usuário definir algo em `--listen`, toda a lógica abaixo é ignorada e o host:porta passado é usado diretamente.
- Se nada for definido pelo usuário em `--listen` e o reproxy for executado fora do container docker, o padrão é `127.0.0.1:80` para modo http (`ssl.type=none`) e `127.0.0.1:443` para modo ssl (`ssl.type=auto` ou `ssl.type=static`).
- Se nada for definido pelo usuário em `--listen` e o reproxy for executado dentro do docker, o padrão é `0.0.0.0:8080` para modo http e `0.0.0.0:8443` para modo ssl.

Outro padrão definido de forma dinâmica semelhante é `--ssl.http-port`. Para execução dentro do container docker, é definido como `8080` e sem docker como `80`.

## Ping, verificações de saúde e fail-over

reproxy fornece dois endpoints para este propósito:

- `/ping` responde com `pong` e indica que o reproxy está ativo e funcionando
- `/health` retorna status `200 OK` se todos os servidores de destino responderem à sua solicitação de ping com `200` ou `417 Expectation Failed` se algum servidor responder com código diferente de 200. Também retorna corpo json com detalhes sobre serviços aprovados/falhos.

Além dos endpoints acima, o reproxy suporta verificações de saúde ao vivo opcionais. Neste caso (se ativado), 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 provedor ou de vários provedores, e apenas os aprovados são selecionados. Se várias correspondências forem descobertas e aprovadas, a final é selecionada de acordo com a estratégia `lb-type` (por padrão seleção aleatória).

Para ativar a verificação de saúde ao vivo, o usuário deve definir `--health-check.enabled` (ou env `HEALTH_CHECK_ENABLED=true`). Para personalizar o intervalo de verificação, pode-se usar `--health-check.interval=`.

## API de Gerenciamento

Opcional, pode ser ativado 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 caminhos de requisição brutos como labels, 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/(.*)`) em vez disso, 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

Reproxy retorna 502 (Bad Gateway) caso a requisição não corresponda a nenhuma rota ou ativo fornecido. Caso ocorra algum erro interno inesperado, 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 renderização do erro. O template tem 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 para a atividade geral do sistema, bem como por usuário. Valores 0 (padrão) são tratados como ilimitados.

Atividade do usuário limitada para rotas correspondidas e não correspondidas. Todas as rotas não correspondidas são consideradas como um "grupo de destino único" e recebem um limitador comum que é `rate*3`. Isso significa que se 10 (req/seg) for definido com `--throttle.user=10`, o usuário final poderá realizar até 30 requisições por segundo para ativos estáticos ou rotas não correspondidas. Para rotas correspondidas, este limitador é mantido por destino (rota), ou seja, a requisição proxy para s1.example.com/api permitirá 10 r/s e a requisição para s2.example.com permitirá outros 10 r/s.

### Timeout e throttle por rota

Rotas individuais podem substituir as configurações globais `--timeout.write` e `--throttle.user` através dos campos `timeout` e `throttle` específicos do provedor. Isso é útil para endpoints de longa execução (por exemplo, uploads, geração de relatórios) que precisam de um prazo maior que o timeout de gravação global, e para apertar limites de taxa em rotas sensíveis (por exemplo, login) sem aumentar o teto global para todo o resto.

Precedência é "zero herda global, positivo substitui": uma rota com `timeout: 0` (ou sem campo `timeout`) mantém o `--timeout.write` global; uma rota com `timeout: 5m` o substitui apenas para requisições correspondidas. A mesma regra se aplica a `throttle`.

O timeout por rota substitui os prazos de leitura e gravação da conexão para requisições correspondidas, portanto pode se estender além do `--timeout.write` global (padrão 30s). Rotas sem timeout por rota ainda respeitam a configuração global.

**Limitação — timeout de cabeçalho de resposta no nível de transporte:** o `timeout` por rota NÃO substitui `--timeout.resp-header` (padrão 5s). Esse timeout é definido no `http.Transport` compartilhado e se aplica antes do upstream começar a enviar cabeçalhos de resposta. Se um upstream demorar mais que `--timeout.resp-header` para iniciar sua resposta (por exemplo, um endpoint de relatório lento), a requisição falha nesse limite, independentemente do `timeout` por rota. Para suportar tais rotas, aumente `--timeout.resp-header` globalmente para o máximo necessário por qualquer rota de resposta lenta. A substituição por rota de timeouts no nível de transporte está intencionalmente fora do escopo.

Sintaxe dos provedores:
- **Provedor de arquivo** (YAML): `timeout: 5m`, `throttle: 2`
- **Provedor estático** (CSV): 6º e 7º campos posicionais, ex. `*,^/upload/(.*),http://up:8080/$1,,,5m,2`
- **Provedor Docker**: `reproxy.timeout=5m`, `reproxy.throttle=2` (ou `reproxy.<n>.timeout` / `reproxy.<n>.throttle` para contêineres com múltiplas rotas)
- **Provedor Consul Catalog**: `reproxy.timeout=5m`, `reproxy.throttle=2`

## Limites de conexão upstream

O reproxy permite configurar as configurações do pool de conexões upstream para controlar quantas conexões são mantidas com os servidores backend:

- `--upstream.max-idle-conns` - Número máximo de conexões ociosas em todos os hosts upstream. Padrão: 100.
- `--upstream.max-conns` - Número máximo de conexões por host upstream (0 = ilimitado). Padrão: 0.

Definir `--upstream.max-conns` limita conexões concorrentes para cada backend, o que é útil quando servidores upstream têm capacidade limitada ou para evitar esgotamento de conexões.

## Autenticação básica

O reproxy suporta autenticação básica em dois modos: global (todas as rotas) e por rota.

### Autenticação básica global

A autenticação básica global protege todas as rotas. Isso é útil para proteger endpoints durante desenvolvimento e testes. Para ativar, defina o arquivo htpasswd com `--basic-htpasswd=<local do arquivo>` ou env `BASIC_HTPASSWD=<local do arquivo>`.

O reproxy espera que o arquivo htpasswd esteja no seguinte formato:```
username1:bcrypt(password1)
username2:bcrypt(password2)
...

isso pode ser gerado com o comando htpasswd -nbB, ou seja, htpasswd -nbB test passwd

Autenticação básica por rota

A autenticação por rota permite credenciais diferentes para rotas diferentes. Quando uma rota possui autenticação por rota configurada, a autenticação global é ignorada para aquela rota. A autenticação por rota é configurada através de configurações específicas do provedor:

  • Provedor de arquivo: campo auth no YAML, por exemplo, auth: "user1:$2y$..., user2:$2y$..."
  • Provedor Docker: label reproxy.auth
  • Provedor Consul Catalog: tag reproxy.auth
  • Provedor estático: não suportado (use o provedor de arquivo para autenticação por rota)

O formato é uma lista separada por vírgulas de pares user:bcrypt_hash (mesmo formato htpasswd). Vários usuários podem ser especificados para a mesma rota.

Exemplo com docker-compose:```yaml services: admin-api: labels: - "reproxy.route=^/admin/(.*)" - "reproxy.dest=/$1" - "reproxy.auth=admin:$$2y$$05$$hashedpassword"

Nota: Em docker-compose, `$` deve ser escapado como `$$`.

## Controle de acesso baseado em IP

Reproxy permite restringir o acesso às rotas com uma lista de sub-redes ou IPs separados por vírgula. Isso é útil para desenvolvimento e testes, antes de permitir acesso irrestrito a elas. Também pode ser usado para restringir acesso a serviços internos. Por padrão, todas as rotas estão abertas para todos os clientes.

Para restringir o acesso às rotas, o usuário deve definir as chaves apropriadas para as rotas, ou seja, `reproxy.remote` para docker e consul, e `remote` para o provedor de arquivos. O valor deve ser uma lista de sub-redes ou IPs separados por vírgula. Por exemplo, `127.0.0.1, 192.168.1.0/24`. Para mais detalhes, consulte as seções [docker provider](#docker-provider) e [consul catalog provider](#consul-catalog-provider).

Por padrão, o reproxy verificará o endereço remoto da solicitação do cliente. No entanto, em alguns casos, isso não funcionará como esperado, por exemplo, atrás de outro proxy ou com a rede bridge do Docker. Isso pode ser alterado com o parâmetro `--remote-lookup-headers`, permitindo verificar o valor do cabeçalho `X-Real-IP` ou `X-Forwarded-For` (nesta ordem) e usá-lo para a verificação. Se o cabeçalho não estiver definido, a verificação será realizada contra o endereço remoto do cliente. Esses cabeçalhos são fornecidos pelo cliente e são trivialmente falsificáveis, portanto, este parâmetro deve ser ativado apenas quando o reproxy estiver atrás de um proxy front-end confiável que sempre define e sobrescreve esses cabeçalhos.

A verificação de cabeçalhos deve ser usada com cautela, pois é possível falsificá-los. Quando `--remote-lookup-headers` está ativado, a lista de permissões de IP depende inteiramente dessa suposição de confiança: um cliente enviando `X-Real-IP` ou `X-Forwarded-For` com um endereço permitido pode, de outra forma, contornar a restrição. Ative esta opção apenas se o reproxy estiver atrás de um proxy confiável que controla esses cabeçalhos e você puder garantir que eles não sejam falsificados.

## Suporte a plugins

A funcionalidade principal do reproxy pode ser estendida com plugins externos. Cada plugin é um processo/contêiner independente que implementa um [servidor RPC](https://golang.org/pkg/net/rpc/). Os plugins são registrados com o condutor do reproxy e adicionados à cadeia de middlewares. Cada plugin recebe uma solicitação com a URL original, cabeçalhos e todas as informações da rota correspondente e responde com os cabeçalhos e o código de status. Qualquer código de status >= 400 é tratado como resposta de erro e encerra o fluxo imediatamente com o erro do proxy. Existem dois tipos de cabeçalhos que os plugins podem definir:

- `HeadersIn` - cabeçalhos de entrada. Estes serão enviados para a URL do proxy
- `HeadersOut` - cabeçalhos de saída. Serão enviados de volta ao cliente

Por padrão, os cabeçalhos definidos por um plugin serão misturados com os cabeçalhos originais. Caso o plugin precise controlar todos os cabeçalhos, por exemplo, descartar alguns, o campo `OverrideHeaders*` pode ser definido por um plugin, indicando ao processo principal do reproxy a necessidade de sobrescrever todos os cabeçalhos em vez de misturá-los.

- `OverrideHeadersIn` - indica que o plugin é responsável por todos os cabeçalhos de entrada.
- `OverrideHeadersOut` - indica que o plugin é responsável por todos os cabeçalhos de saída

Para simplificar o processo de desenvolvimento, todos os blocos de construção são fornecidos. Inclui `lib.Plugin` que lida com registro, escuta e despacho de chamadas, bem como `lib.Request` e `lib.Response` que definem entrada e saída. Os autores dos plugins devem implementar manipuladores concretos que satisfaçam a assinatura `func(req lib.Request, res *lib.HandlerResponse) (err error)`. Cada plugin pode conter vários manipuladores como este.

_Veja [examples/plugin](https://github.com/umputun/reproxy/tree/master/examples/plugin) para mais informações_

## Segurança do contêiner

Por padrão, o contêiner reproxy é executado sob o usuário root para simplificar a configuração inicial e acessar o socket do Docker. Isso é necessário para permitir que o provedor Docker descubra os contêineres em execução. No entanto, se tal descoberta não for necessária ou o provedor Docker não estiver em uso, é recomendável alterar o usuário para um com menos privilégios. Isso pode ser feito no nível do docker-compose e no nível do docker com a opção `user`; veja a seção abaixo para detalhes.

Às vezes, mesmo com roteamento dentro do Docker, faz sentido desabilitar o provedor Docker e configurar regras com o provedor estático ou de arquivos. Todos os contêineres em execução dentro de um compose compartilham a mesma rede e são acessíveis via DNS local. O usuário pode ter uma regra como esta para evitar a descoberta do Docker: `- STATIC_RULES=*,/api/email/(.*),http://email-sender:8080/$$1`. Esta regra espera que o contêiner `email-sender` esteja definido dentro do mesmo compose. Observe: os usuários podem obter o mesmo resultado usando a rede Docker mesmo que o serviço de destino tenha sido definido em um arquivo compose diferente. Dessa forma, a configuração do reproxy pode permanecer separada dos serviços reais.

Não há nada além do binário reproxy dentro do contêiner reproxy, pois ele é construído sobre uma imagem vazia (scratch).

### Executando com um usuário não root

Um usuário com UID `1001` (pertencente aos grupos `1001` e `999`) é pré-criado dentro do contêiner e pode ser usado para executar o reproxy como um usuário não root:```yaml
services:
  reproxy:
    user: 1001
    image: umputun/reproxy:latest
# <...>
# see examples/ssl/docker-compose.yml for the full file example

Se você quiser usar o provedor Docker, precisará garantir que este usuário tenha permissão para acessar o socket Docker no sistema host. A forma de configurar essas permissões depende da configuração do seu sistema host. Para mais informações sobre como configurar permissões do socket Docker, consulte a documentação do Docker sobre como proteger o socket do daemon Docker.

Opções

Cada opção pode ser fornecida de duas formas: linha de comando ou par chave:valor de ambiente. Algumas opções de linha de comando têm uma forma abreviada, como -l localhost:8080 e todas têm a forma longa, i.e. --listen=localhost:8080. A chave de ambiente (nome) listada para cada opção como um sufixo, i.e. [$LISTEN].

Todas as opções de tamanho suportam sufixos de unidade, i.e. 10K (ou 10k) para kilobytes, 16M (ou 16m) para megabytes, 10G (ou 10g) para gigabytes. A ausência de qualquer sufixo (i.e. 1024) significa bytes.

Algumas opções são repetíveis; neste caso, o usuário pode passá-las várias vezes na linha de comando, ou separadas por vírgula no ambiente. Por exemplo, --ssl.fqdn é uma dessas opções e pode ser passada como --ssl.fqdn=a1.example.com --ssl.fqdn=a2.example.com ou como variável de ambiente SSL_ACME_FQDN=a1.example.com,a2.example.com

Esta é a lista de todas as opções que suportam múltiplos elementos:

  • ssl.fqdn (SSL_ACME_FQDN)
  • assets.cache (ASSETS_CACHE)
  • docker.exclude (DOCKER_EXCLUDE)
  • static.rule ($STATIC_RULES)
  • header ($HEADER)
  • drop-header ($DROP_HEADERS)

All Application Options```

-l, --listen= listen on host:port (default: 0.0.0.0:8080/8443 under docker, 127.0.0.1:80/443 without) [$LISTEN] -m, --max= max request size (default: 64K) [$MAX_SIZE] -g, --gzip enable gz compression [$GZIP] -x, --header= outgoing proxy headers to add [$HEADER] --drop-header= incoming headers to drop [$DROP_HEADERS] --basic-htpasswd= htpasswd file for basic auth [$BASIC_HTPASSWD]
--lb-type=[random|failover|roundrobin] load balancer type (default: random) [$LB_TYPE] --signature enable reproxy signature headers [$SIGNATURE] --remote-lookup-headers enable remote lookup headers, trust only behind a trusted proxy [$REMOTE_LOOKUP_HEADERS] --keep-host keep original Host header as default when proxying [$KEEP_HOST] --insecure skip SSL verification on destination host [$INSECURE] --dbg debug mode [$DEBUG]

ssl: --ssl.type=[none|static|auto] ssl (auto) support (default: none) [$SSL_TYPE] --ssl.cert= path to cert.pem file [$SSL_CERT] --ssl.key= path to key.pem file [$SSL_KEY] --ssl.acme-location= dir where certificates will be stored by autocert manager (default: ./var/acme) [$SSL_ACME_LOCATION] --ssl.acme-email= admin email for certificate notifications [$SSL_ACME_EMAIL] --ssl.http-port= http port for redirect to https and acme challenge test (default: 8080 under docker, 80 without) [$SSL_HTTP_PORT] --ssl.fqdn= FQDN(s) for ACME certificates [$SSL_ACME_FQDN]

assets: -a, --assets.location= assets location [$ASSETS_LOCATION] --assets.root= assets web root (default: /) [$ASSETS_ROOT] --assets.spa spa treatment for assets [$ASSETS_SPA] --assets.cache= cache duration for assets [$ASSETS_CACHE] --assets.not-found= path to file to serve on 404, relative to location [$ASSETS_NOT_FOUND]

logger: --logger.stdout enable stdout logging [$LOGGER_STDOUT] --logger.enabled enable access and error rotated logs [$LOGGER_ENABLED] --logger.file= location of access log (default: access.log) [$LOGGER_FILE] --logger.max-size= maximum size before it gets rotated (default: 100M) [$LOGGER_MAX_SIZE] --logger.max-backups= maximum number of old log files to retain (default: 10) [$LOGGER_MAX_BACKUPS]

docker: --docker.enabled enable docker provider [$DOCKER_ENABLED] --docker.host= docker host (default: unix:///var/run/docker.sock) [$DOCKER_HOST] --docker.network= docker network [$DOCKER_NETWORK] --docker.exclude= excluded containers [$DOCKER_EXCLUDE] --docker.auto enable automatic routing (without labels) [$DOCKER_AUTO] --docker.prefix= prefix for docker source routes [$DOCKER_PREFIX] --docker.api-version= docker API version (default: 1.24) [$DOCKER_API_VERSION]

consul-catalog: --consul-catalog.enabled enable consul catalog provider [$CONSUL_CATALOG_ENABLED] --consul-catalog.address= consul address (default: http://127.0.0.1:8500) [$CONSUL_CATALOG_ADDRESS] --consul-catalog.interval= consul catalog check interval (default: 1s) [$CONSUL_CATALOG_INTERVAL]

file: --file.enabled enable file provider [$FILE_ENABLED] --file.name= file name (default: reproxy.yml) [$FILE_NAME] --file.interval= file check interval (default: 3s) [$FILE_INTERVAL] --file.delay= reload only after the file has been unchanged for this long (default: 500ms) [$FILE_DELAY]

static: --static.enabled enable static provider [$STATIC_ENABLED] --static.rule= routing rules [$STATIC_RULES]

timeout: --timeout.read-header= read header server timeout (default: 5s) [$TIMEOUT_READ_HEADER] --timeout.write= write server timeout (default: 30s) [$TIMEOUT_WRITE] --timeout.idle= idle server timeout (default: 30s) [$TIMEOUT_IDLE] --timeout.dial= dial transport timeout (default: 30s) [$TIMEOUT_DIAL] --timeout.keep-alive= keep-alive transport timeout (default: 30s) [$TIMEOUT_KEEP_ALIVE] --timeout.resp-header= response header transport timeout (default: 5s) [$TIMEOUT_RESP_HEADER] --timeout.idle-conn= idle connection transport timeout (default: 90s) [$TIMEOUT_IDLE_CONN] --timeout.tls= TLS hanshake transport timeout (default: 10s) [$TIMEOUT_TLS] --timeout.continue= expect continue transport timeout (default: 1s) [$TIMEOUT_CONTINUE]

mgmt: --mgmt.enabled enable management API [$MGMT_ENABLED] --mgmt.listen= listen on host:port (default: 0.0.0.0:8081) [$MGMT_LISTEN] --mgmt.low-cardinality use route patterns instead of raw paths for metrics labels [$MGMT_LOW_CARDINALITY]

error: --error.enabled enable html errors reporting [$ERROR_ENABLED] --error.template= error message template file [$ERROR_TEMPLATE]

health-check: --health-check.enabled enable automatic health-check [$HEALTH_CHECK_ENABLED] --health-check.interval= automatic health-check interval (default: 300s) [$HEALTH_CHECK_INTERVAL]

throttle: --throttle.system= throttle overall activity' (default: 0) [$THROTTLE_SYSTEM] --throttle.user= limit req/sec per user and per proxy destination (default: 0) [$THROTTLE_USER]

upstream: --upstream.max-idle-conns= max idle connections total (default: 100) [$UPSTREAM_MAX_IDLE_CONNS] --upstream.max-conns= max connections per upstream host (0=unlimited) (default: 0) [$UPSTREAM_MAX_CONNS]

plugin: --plugin.enabled enable plugin support [$PLUGIN_ENABLED] --plugin.listen= registration listen on host:port (default: 127.0.0.1:8081) [$PLUGIN_LISTEN]

Help Options: -h, --help Show this help message

## Status

O projeto está em desenvolvimento ativo e pode ter mudanças significativas até que a versão `v1` seja lançada. No entanto, estamos nos esforçando ao máximo para não quebrar nada, a menos que haja um bom motivo. A partir da versão 0.4.x, o reproxy é considerado suficientemente maduro para uso em cenários reais, e muitas configurações já o utilizam em produção.

Categorias