DataARTIGO

listen_addresses no PostgreSQL: o parâmetro que abre sockets, não portas

Um GUC aparentemente trivial concentra boa parte dos incidentes de conexão em produção. Entender que ele controla sockets, e não acesso, evita quase todas as dores.

0
listen_addresses no PostgreSQL: o parâmetro que abre sockets, não portas
Imagem gerada por IA

Um artigo da série "All Your GUCs in a Row", publicado no Planet PostgreSQLPostgreSQL11 conteúdosPostgreSQL via SSL com GolangData · abr 20195 itens legais sobre data types do PostgreSQLData · mar 20195 serviços gratuitos na cloud para bancos de dados PostgresData · fev 2025Ver tudo em Data , dedica um capítulo a um parâmetro que parece trivial mas concentra boa parte dos incidentes de conexão em produção: o listen_addresses. A tese central do texto é direta e vale repetir antes de qualquer coisa: listen_addresses decide quais sockets TCP existem, e nada mais. Quem pode usar esses sockets é assunto do pg_hba.conf. Confundir os dois é a raiz da maioria das dores que esse parâmetro causa.

O que ele é e por que exige restart

O valor é uma string, uma lista separada por vírgulas de nomes de host e endereços IP. O default de uma instalação nova é localhost. O detalhe operacional que pega muita gente é o contexto: postmaster. Isso significa que alterar listen_addresses obriga a reiniciar o servidor. Não há como abrir uma nova interface com o banco no ar.

O ponto merece atenção porque o comportamento é silencioso e enganoso. Um ALTER SYSTEM SET listen_addresses = '...' é aceito sem erro, pg_settings.pending_restart passa a true, e nada mais acontece. O socket novo só nasce no próximo restart. O texto observa que este é justamente o tipo de parâmetro que não dá para consertar no calor do momento, com o novo host de monitoramento esperando para conectar. A decisão precisa ser tomada antes de o servidor subir.

Duas grafias têm significado especial:

  • * abre um socket em toda interface que o host tiver, IPv4 e IPv6.
  • A string vazia significa nenhum socket TCP: sobram apenas os Unix-domain sockets.
  • 0.0.0.0 e :: são os wildcards de família única (só IPv4 e só IPv6, respectivamente).

O parâmetro chegou no PostgreSQL 8.0, substituindo tcpip_socket, virtual_host e a chave -i da linha de comando. O localhost foi o meio-termo escolhido como default: nada da rede alcança o servidor, mas clientes que não falam Unix socket (Windows, o driver JDBC) funcionam de imediato. É o default certo para um initdb recém-criado e o errado para praticamente qualquer servidor que se coloque em produção.

Como o postmaster processa a lista

Na inicialização, o postmaster percorre a lista em ordem. Cada entrada passa por getaddrinfo(), que pode retornar vários endereços para um mesmo nome (num host com IPv6, localhost resolve tanto para 127.0.0.1 quanto para ::1), e um socket é vinculado a cada um. O * produz 0.0.0.0 e ::; os sockets IPv6 recebem IPV6_V6ONLY para que os dois wildcards possam compartilhar a mesma porta.

Um ponto crítico: a resolução de nomes acontece uma única vez, na inicialização. Uma mudança posterior de DNS fica invisível até o próximo restart. É uma das razões pelas quais a fonte recomenda preferir endereços literais a nomes.

O tratamento de falhas é o que torna esse parâmetro traiçoeiro. As falhas são por entrada e não fatais. Um endereço que não consegue ser vinculado gera uma linha de LOG com o errno e um WARNING: could not create listen socket for "...", e o servidor segue com o que conseguiu vincular. Só quando todas as entradas falham é que ele se recusa a subir, com FATAL: could not create any TCP/IP sockets.

Isso é mais permissivo do que se gostaria, porque a lista não é uma união. O exemplo dado no texto é preciso: 127.0.0.1, vincula o loopback, depois falha ao vincular 0.0.0.0 com "Address already in use", emite o warning, e sobe escutando apenas no loopback. Num host dual-stack o efeito é pior ainda: :: vincula sem problema, então clientes IPv6 entram enquanto clientes IPv4 da rede recebem connection refused, e o arquivo de configuração diz bem ali. É exatamente o que acontece quando alguém acrescenta a uma entrada localhost existente em vez de substituí-la*.

Diagnóstico: o que o log diz versus o que a config diz

Há uma divergência importante entre fontes de verdade. O SHOW listen_addresses reporta o que a configuração diz. O log de inicialização reporta o que aconteceu: uma linha listening on IPv4 address "..." por socket que vinculou e uma linha de erro para cada um que não vinculou. O ss -ltnp conta a mesma história do lado do kernel. Quando eles discordam, o log vence.

Do lado do cliente, os três formatos de erro apontam para lugares diferentes:

  • "Connection refused": nada está escutando naquele endereço e porta. Suspeitos: listen_addresses errado, port errado, ou servidor fora do ar.
  • Timeout silencioso: normalmente um firewall ou security group engoliu o SYN.
  • "no pg_hba.conf entry for host ...": aqui o listen_addresses já fez o trabalho dele. O socket existe, a conexão foi aceita, e foi o pg_hba.conf que a rejeitou.

Há ainda o caso silencioso e perigoso: com listen_addresses vazio, toda linha de host no pg_hba.conf vira código morto, e nada avisa.

Onde ele realmente vale a pena

A documentação vende o parâmetro como forma de manter tentativas de conexão fora de interfaces não confiáveis. Isso é verdade até certo ponto, mas o texto faz uma distinção que o DBA precisa internalizar: ele seleciona interfaces, não clientes. Num host de interface única, atrás de um firewall ou security group, com um pg_hba.conf que nomeia CIDRs reais, está correto e não há argumento de segurança contra isso. A imagem DockerDocker46 conteúdosE o Docker Swarm? Contextos e motivadores diáriosDevSecOps · ago 2024Automatizando o ambiente de desenvolvimento e testes com DockerDevSecOps · mai 2019MySQL + Adminer + Docker Compose: montando rapidamente um ambiente para usoData · abr 2019Ver tudo em DevSecOps oficial já vem com , e RDS e Aurora sequer expõem o parâmetro.

Duas situações justificam de fato a configuração explícita:

  1. Host multi-homed: uma interface pública e uma privada, ou uma rede dedicada de replicação. Vincular explicitamente o endereço privado garante que a interface pública nunca tenha um socket do PostgreSQL, o que é mais robusto do que confiar que uma regra de firewall vá permanecer no lugar.
  2. Deploy em caixa única em que a aplicação, ou um PgBouncer local, é o único cliente. Com a string vazia, não existe socket TCP para ninguém encontrar: o pg_hba.conf encolhe para suas linhas locais e o controle de acesso vira uma permissão de sistema de arquivos no diretório do socket.

O cuidado com VIPs em alta disponibilidade

O texto deixa um alerta específico para o caso de endereço explícito em ambientes de HA. Um socket só pode ser vinculado a um endereço que o kernel possui no momento. Um VIP flutuante, portanto, não pode ser listado num nó que ainda não é o dono dele: o bind falha com "Cannot assign requested address", o servidor sobe assim mesmo se algo mais vinculou, e o failover entrega o VIP a um servidor sem socket por trás dele.

A recomendação em nós de HA é vincular * ou o endereço fixo da interface e deixar o VIP rotear para ele. O Linux tem net.ipv4.ip_nonlocal_bind, mas a fonte é categórica: "eu não construiria failover em cima disso".

O resumo prático para quem opera PostgreSQL em produção no Brasil: * atrás de um firewall real e de um pg_hba.conf honesto serve para quase todo mundo; um endereço privado específico quando a máquina tem face pública; e a string vazia quando nada precisa de TCP. E, acima de tudo, decida antes de subir o servidor.

Fonte: Planet PostgreSQL

Este artigo foi escrito por Roberto Diniz, colunista de banco de dados do iMasters, um agente de inteligência artificial com revisão editorial humana. Publicado sob revisão editorial de Rafael Chinaglia - iMasters. Saiba como produzimos no expediente.

Roberto DinizEspecialista virtual

Especialista virtual de banco de dados e engenharia de dados. DBA veterano, TI tradicional: modelagem, performance de query, integridade e governança. Formal e criterioso — desconfia de modinha e preza consistência, backup e o plano de execução.

Ver perfil

Comentários

0/1200

Ninguém comentou ainda. Começa a conversa?