Skip to content
mobius1qwe edited this page Nov 4, 2026 · 1 revision

Home > Colocar no ar > RALProxy 🚧

RALProxy: um balanceador no modelo do NGINX

Important

Em desenvolvimento (2.0). Ainda não está numa versão lançada e pode mudar.

Vale para a 2.0 · Delphi XE em diante e Lazarus/FPC 3.2 em diante · Nível: intermediário

Em uma frase: um programa pronto (exemplo dos Samples, Delphi e Lazarus) que lê um arquivo de configuração com a sintaxe do NGINX, abre as portas com o TRALBalancer, grava o log de acesso e recarrega a configuração sem derrubar as conexões abertas - como console, serviço do Windows ou daemon do Linux.

Você vai precisar: os Samples da 2.0 (Delphi/Console/RALProxy ou Lazarus/Console/RALProxy), os pacotes PascalRAL, RALNetPackage e RALModuleProxyPackage, e para HTTPS a OpenSSL ao lado do programa (dependências).

Uso

ralproxy -t -c ralproxy.conf     confere e sai (como nginx -t)
ralproxy -c ralproxy.conf        roda; Ctrl+C ou SIGTERM termina

Sem -c, lê o ralproxy.conf da pasta do programa. Recarregar: kill -HUP <pid> no Linux (systemctl reload ralproxy), ou salvar o arquivo no Windows (olhado a cada 2 s). O serviço do Windows (RALProxyService, só Delphi) e a unidade do systemd (ralproxy.service) estão no exemplo, com os comandos de instalação.

Um arquivo de exemplo

worker_threads auto;
error_log logs/erro.log;
pid ralproxy.pid;

http {
  access_log logs/acesso.log combined;
  proxy_read_timeout 60s;

  upstream api {
    least_conn;
    server 127.0.0.1:8101 weight=2;
    server 127.0.0.1:8102 max_fails=2 fail_timeout=10s;
    server 127.0.0.1:8103 backup;
    health_check uri=/health interval=5s fails=3 passes=2;
  }

  server {
    listen 443 ssl;
    server_name api.exemplo.com;
    ssl_certificate certs/api.pem;
    ssl_certificate_key certs/api.key;
    location /v1/ { proxy_pass http://api/; }      # /v1/x vai como /x
  }

  server {
    listen 80;
    location = /status { stub_status; }
    location / { proxy_pass http://api; }
  }
}

stream {
  upstream banco { server 10.0.0.20:5432; }
  server { listen 5432; proxy_pass banco; }
}

Como ele lê

  • É um subconjunto da sintaxe do NGINX, lido por um analisador do próprio RAL (TRALProxyConfig). Uma diretiva que ele não conhece é erro, nunca ignorada, e o erro diz o arquivo, a linha e a coluna: ralproxy.conf:12:5: unknown directive "servr" in http.
  • include arquivo; e include pasta/*.conf; (em ordem de nome) entram onde estão; caminho relativo é relativo ao arquivo que inclui.
  • Comentários com #; valores com espaço entre aspas.
  • Tempos: 500ms, 30s, 5m, 1h, 1d (número sozinho é segundos). Tamanhos: 16k, 1m.
  • Os server de um mesmo listen dividem a porta: os com server_name primeiro, e dentro de cada nome o location de prefixo mais longo primeiro (como o NGINX); depois o server sem nome ou, sem ele, o primeiro da porta (o servidor padrão do NGINX).

As diretivas

Fora dos blocos

diretiva o quê
worker_threads N; (ou worker_processes) threads de cada porta; auto = uma por processador
error_log arquivo; onde vão os erros (sem ele: a saída de erro)
pid arquivo; grava o número do processo (para o kill -HUP)
events { worker_connections N; } aceito e ignorado

http { }

diretiva o quê
access_log arquivo [combined|json]; / access_log off; log de acesso
keepalive_timeout 75s; IdleTimeout
client_header_timeout 30s; HeaderTimeout
proxy_read_timeout 60s; ServerTimeout (servidor mudo: 504)
proxy_connect_timeout 5s; ConnectTimeout de todos os upstreams
proxy_buffer_size 16k; BufferSize
large_client_header_buffers 4 16k; MaxHeaderSize (o último valor)
sendfile, tcp_nodelay aceitos (o RAL sempre tem)

keepalive_timeout, client_header_timeout, proxy_read_timeout, proxy_buffer_size e large_client_header_buffers valem também dentro de um server, só para a porta dele.

upstream nome { } (em http e em stream)

diretiva o quê
server host:porta [weight=N] [max_fails=N] [fail_timeout=10s] [max_conns=N] [backup] [down]; um servidor; https://host:porta chama com TLS
least_conn; / ip_hash; / random two; a política
hash $request_uri consistent; hash consistente pelo caminho; $http_<cabeçalho>, $cookie_<nome>, $remote_addr também
sticky cookie nome; sessão grudada pelo cookie
health_check uri=/health interval=5s fails=3 passes=2 timeout=2s status=200; verificação ativa
keepalive N; aceito (as conexões são sempre mantidas)

server { } de http

diretiva o quê
listen 80; / listen 10.0.0.1:443 ssl; a porta (e o endereço); ssl termina TLS aqui
server_name a.exemplo.com *.b.exemplo.com; os nomes (_ é nenhum)
ssl_certificate / ssl_certificate_key o certificado deste server (escolhido pelo SNI)
ssl_protocols TLSv1.2 TLSv1.3; a versão mínima
location /prefixo/ { ... } / location = /caminho { ... } prefixo (sem expressões regulares)

location { }

diretiva o quê
proxy_pass http://upstream; repassa como veio
proxy_pass http://upstream/; tira o prefixo do location (/v1/x vai como /x)
proxy_pass http://10.0.0.5:8080; um servidor só, sem bloco upstream
proxy_set_header Host $host; passa o Host do cliente (é a única forma aceita)
stub_status; a estatística do balanceador (JSON; ?format=prometheus)
proxy_http_version 1.1; aceito

stream { server { } }

diretiva o quê
listen 5432; a porta (sem ssl: TLS passa sem abrir)
server_name a.exemplo.com; escolhe pelo SNI do ClientHello (vários server na mesma porta)
proxy_pass upstream; / proxy_pass host:porta; para onde vão os bytes
proxy_timeout 10m; TunnelTimeout
proxy_connect_timeout 5s; ConnectTimeout
ssl_preread on; aceito (o RAL lê o ClientHello sempre que há server_name)

Recarga

As portas que ficam continuam abertas, e as conexões que já existem seguem: o próximo pedido delas usa as rotas novas. Portas novas abrem antes de qualquer coisa mudar; se uma não abre (ocupada), a recarga é recusada e a configuração anterior continua rodando, com o motivo no error_log. Uma porta que troca de http para stream, ou liga e desliga o ssl, fecha e abre de novo.

No seu programa

O que o RALProxy faz está em duas classes da biblioteca (RALProxyConfig):

Config := TRALProxyConfig.Create;
Config.LoadFromFile('ralproxy.conf');   // ERALProxyConfigError com Line e Column
Host := TRALProxyHost.Create;
Host.OnAccess := MeuLog;
Host.Start(Config);                     // o Host fica com a configuração
...
Nova := TRALProxyConfig.Create;
Nova.LoadFromFile('ralproxy.conf');
Host.Reload(Nova);

Erros comuns

Sintoma Causa Solução
unknown directive numa diretiva do NGINX ela não está no subconjunto veja as tabelas acima; o RAL não ignora o que não entende
port N listens with ssl but this server has no ssl_certificate listen ... ssl sem certificado no mesmo server ponha ssl_certificate e ssl_certificate_key
port N is taken twice dois stream sem nome na mesma porta, ou http e stream use server_name ou outra porta
a recarga não pega erro no arquivo (veja o error_log) ou, no Windows, o arquivo não foi salvo de novo ralproxy -t mostra o erro
a porta 80 não abre no Linux porta abaixo de 1024 sem ser root AmbientCapabilities=CAP_NET_BIND_SERVICE (já no ralproxy.service)

Veja também

Clone this wiki locally