Ir para o conteúdo

Mostrar o teu domínio personalizado no navegador de servidores do FiveM

Este guia explica, de uma ponta à outra, como pôr o teu domínio próprio (por exemplo play.example.com) a aparecer no navegador de servidores dentro do FiveM quando os jogadores procuram o teu servidor, e como fazer com que connect play.example.com funcione a partir da consola F8.

Vamos cobrir:

  • O que a Zaroz Cloud configura automaticamente quando associas um domínio à tua encomenda.
  • As linhas extra que tens de pôr no server.cfg para o domínio aparecer de facto na lista (em vez do IP cru).
  • Como funciona por dentro o backend de listagem da cfx.re, para que consigas depurar quando alguma coisa falha.
  • A configuração avançada (com proxy reverso próprio) se quiseres esconder o IP por completo para proteção DDoS.

Como é que um domínio chega sequer à lista de servidores

Antes de tocar em qualquer config, precisas do modelo mental. O FiveM faz duas coisas completamente diferentes por dois caminhos completamente diferentes:

  1. Entrar no servidor escrevendo connect <nome> na consola F8. Este caminho usa DNS. O cliente vai buscar um registo SRV (_cfx._udp.<o-teu-dominio>) para descobrir a porta, depois um registo A para descobrir o IP, e liga-se. Nunca pergunta nada ao backend de listagem da cfx.re.

  2. Procurar (ou entrar no) servidor pelo navegador dentro do jogo. Este caminho usa o backend de listagem da cfx.re. O backend bate periodicamente em o teu servidor numa URL do tipo https://<host>/dynamic.json para refrescar os dados da lista. Quando um jogador carrega em "Connect" no navegador, o backend devolve ao cliente um campo connectEndPoints que lhe diz onde se deve ligar de verdade. É esse connectEndPoints que decide se o jogador vê o teu IP ou o teu domínio.

Os dois caminhos são independentes: os registos SRV fazem com que o comando connect funcione, mas não têm qualquer efeito sobre o que o navegador do jogo mostra. Para controlar o navegador, tens de dizer ao teu próprio servidor que domínio anunciar ao backend de listagem.

As regras oficiais sobre como o cliente resolve um destino de ligação estão resumidas na documentação de proxy da Cfx.re:

  • Hosts a seco (por ex. play.example.com) resolvem para http://play.example.com:30120/.
  • Hosts com porta (por ex. play.example.com:30121) resolvem para http://play.example.com:30121/.
  • URLs com esquema (por ex. https://play.example.com/) são usadas tal como estão, com as portas por defeito do esquema (80/443).

Essa última regra é a mais importante para a lista: se quiseres que a lista entregue aos jogadores uma URL limpa https://play.example.com/ (sem porta e sem esquema para escrever), o backend de listagem tem de conseguir chegar ao teu servidor exatamente nessa URL.

O que a Zaroz Cloud faz por ti

Quando associas um domínio à tua encomenda no painel (Página da encomenda → separador External Access → Custom domain):

  1. Pegamos no parent domain que escolheste (por ex. play.zaroz.cloud) e no subdomínio que escreveste (por ex. myserver), formando o host completo, por ex. myserver.play.zaroz.cloud.
  2. Através da Cloudflare, criamos um registo A para esse host a apontar para o IP público que reservámos para a tua encomenda.
  3. Para encomendas de FiveM, criamos também um registo SRV em _cfx._udp.<o-teu-host> a apontar de volta para o mesmo host com a porta UDP de jogo da tua encomenda. (No Minecraft é _minecraft._tcp.<host>, no Factorio _factorio._udp.<host>.)
  4. Um job de reconciliação em segundo plano mantém os dois registos sincronizados se a tua encomenda for movida para outro nó ou tiver a porta reatribuída.

O efeito resumido é que assim que o domínio fica associado, os jogadores já conseguem entrar com connect myserver.play.zaroz.cloud a partir da consola F8, mesmo sem porta. O SRV diz ao cliente do FiveM por que porta UDP entrar, e o A dá-lhe o IP.

O que isto não faz por si só: não muda aquilo que o navegador de servidores dentro do jogo mostra. Isso continua a exigir alterações no teu server.cfg.

Configuração mínima no server.cfg para o navegador de servidores

Se só precisares do fluxo connect por SRV (escrever o endereço na consola F8), não tens de tocar em nada no server.cfg. Os registos que criamos chegam.

Se quiseres que o navegador de servidores mostre o teu domínio quando os jogadores procuram o teu servidor, mete estas linhas no server.cfg, perto do topo:

# Faz de conta que não tens IP estática. Força o backend a usar
# connectEndPoints/sv_listingHostOverride em vez de deixar escapar o IP.
sv_forceIndirectListing true

# Diz ao backend que host consultar e que host entregar ao jogador
# no botão "Connect".
sv_listingHostOverride "http://myserver.play.zaroz.cloud:30120/"

Usa a forma URL completa, não só o host:

  • O esquema (http://) diz ao backend que o teu servidor fala HTTP simples, não HTTPS. O endpoint por defeito do FXServer é HTTP, não HTTPS.
  • A porta (:30120) é a porta real de jogo/HTTP do teu contentor. Se a deixares de fora, o backend assume a porta 80, em que o FXServer não está a ouvir, e o heartbeat falha.

Na Zaroz Cloud, o teu <porta> é o valor que aparece no topo do server.cfg, na linha endpoint_add_tcp "0.0.0.0:<porta>" que o nosso entrypoint reescreve a cada arranque do contentor. Também o tens à mão no painel, em Página da encomenda → External Access → Player connection:

Painel Player connection com o endereço e a porta do servidor

A parte depois dos dois pontos em Server address é a porta que tens de meter em sv_listingHostOverride.

Depois de um reinício, o master normalmente apanha o override em poucos minutos e começa a anunciar o teu host na lista. A secção "Como confirmar que funcionou" mais abaixo mostra como verificar.

Porque é precisa cada linha

sv_forceIndirectListing true

Da documentação oficial: "prevents the server list from advertising your server using its actual IP" (impede que a lista anuncie o teu servidor com o IP real).

Com isto desligado, a lista continua a publicar o IP cru independentemente do que diga sv_listingHostOverride, porque o backend parte do princípio de que qualquer cliente se pode ligar diretamente ao IP de origem e que o override só é usado internamente para o heartbeat. Com isto ligado, o IP é suprimido e o campo connectEndPoints leva o host em vez disso.

sv_listingHostOverride

Da documentação oficial: "makes the server list backend request https://server1.example.com/ instead of the default" (faz com que o backend peça https://server1.example.com/ em vez do endereço por defeito).

Cumpre dois papéis ao mesmo tempo:

  1. Para onde o backend te bate. O heartbeat da cfx.re bate em <host>/dynamic.json, <host>/info.json e <host>/players.json nesta URL.
  2. O que os jogadores veem / a onde se ligam. Quando a listagem indireta está ligada, este mesmo valor é devolvido aos clientes como connectEndPoints, que é o que alimenta o botão "Connect" no navegador.

Por causa deste duplo papel, o valor tem de ser alcançável a partir da internet pública. Na Zaroz, o endpoint HTTP do teu contentor está atado a 0.0.0.0:<a-tua-porta> e o teu registo A já aponta o host para o IP certo, por isso http://<host>:<porta>/ funciona sem infraestrutura extra.

E o sv_listingIpOverride?

Normalmente não precisas de o mexer na Zaroz Cloud. Da documentação oficial: "this value is only needed if the server list backend can't guess the IP to query itself, and is not provided to any front-end connection" (só é necessário se o backend não conseguir adivinhar sozinho o IP a consultar, e não é entregue a nenhuma ligação de cliente).

O nosso entrypoint já escreve o sv_listingIpOverride certo para o IP público que te reservámos, em cada arranque do contentor. É o IP que o master usa para encontrar o teu dynamic.json quando não há host override. Com sv_listingHostOverride posto, o override de IP fica praticamente redundante mas não estorva.

E o sv_endpoints?

sv_endpoints é "the actual endpoint your server is hosted on, or one or multiple server endpoint proxies" (o endpoint real onde o teu servidor está, ou um ou vários proxies de endpoint).

Num setup à pelo, sem proxy, não precisas dele: o backend de listagem vai usar o IP a que bate e a porta que descobre. Só o pões se meteres o teu próprio proxy reverso ou túnel anti-DDoS entre os jogadores e o FXServer, e for preciso dizer aos jogadores para se ligarem ao IP/porta do proxy e não aos do FXServer.

Registos DNS, na íntegra

Caso queiras confirmar do lado da Cloudflare aquilo que pusemos, é assim que um domínio personalizado da Zaroz a funcionar se parece:

;; Registo A
myserver.play.zaroz.cloud.   60   IN   A   188.213.7.49

;; Registo SRV (FiveM)
_cfx._udp.myserver.play.zaroz.cloud.  60  IN  SRV  0 0 32541 myserver.play.zaroz.cloud.

Campos, por ordem: prioridade (0), peso (0), porta (a porta UDP de jogo da tua encomenda, por ex. 32541), alvo (o teu host, terminado em ponto).

O IP e a porta são placeholders; vão refletir o que o kernel tinha atribuído à tua encomenda no momento de criar o registo. Se a tua encomenda for movida para outro nó ou tiver a porta reatribuída, o job de reconciliação reescreve ambos.

Como confirmar que funcionou

Depois de reiniciares o servidor com o novo server.cfg, tens três formas de verificar.

1. Bater nos endpoints pelo browser

Estes devem devolver todos JSON (ou pelo menos HTTP 200):

  • http://<o-teu-dominio>:<a-tua-porta>/info.json
  • http://<o-teu-dominio>:<a-tua-porta>/players.json
  • http://<o-teu-dominio>:<a-tua-porta>/dynamic.json

Se algum bloqueia em timeout ou dá erro de ligação, o master também não consegue chegar. Verifica a firewall e confirma que a URL em sv_listingHostOverride bate certo com o que o contentor está mesmo a ouvir.

2. Olhar para a consola do servidor

Depois do arranque, procura linhas de log de [citizen-server-impl]. Um servidor saudável acaba por registar heartbeats bem-sucedidos. Se vires Server list query returned an error: server request failed for endpoint http://<host>:<porta>/dynamic.json, é porque o master tentou chegar ao override e falhou; a causa mais comum (atraso na cache de license key) está descrita no guia do erro Server list query.

3. Usar a API pública de servidores

Vai a https://servers.fivem.net/api/servers/single/<o-teu-cfx-id> (o cfx ID é a string curta alfanumérica que aparece no URL do teu listagem dentro do jogo) e procura o campo connectEndPoints no JSON. Quando o override se propagar, esse campo deve conter o teu domínio, não o IP cru.

Avançado: com o teu próprio proxy reverso

A configuração básica em cima esconde o teu IP na lista de servidores, mas um atacante decidido ainda o consegue descobrir batendo direto na porta de jogo com os pacotes certos. Se quiseres esconder o IP por completo (por exemplo, atrás de um túnel Cloudflare Spectrum ou de um nginx teu noutro IP), precisas mesmo de um proxy reverso.

Esquema de referência, adaptado da documentação oficial de proxy e do gist da comunidade com nginx:

# Proxy ao nível HTTP: 443 → HTTP na porta de jogo do FXServer
upstream fivem_http {
    server <o-teu-ip-da-zaroz>:<a-tua-porta>;
}

server {
    listen 443 ssl http2;
    server_name myserver.example.com;

    ssl_certificate     /etc/letsencrypt/live/myserver.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/myserver.example.com/privkey.pem;

    location / {
        proxy_pass http://fivem_http;
        proxy_set_header Host             $host;
        proxy_set_header X-Real-IP        $remote_addr;
        proxy_set_header X-Forwarded-For  $remote_addr;
        proxy_http_version 1.1;
    }

    location /files/ {
        proxy_pass        http://fivem_http$request_uri;
        proxy_cache       assets;
        proxy_cache_valid 1y;
    }
}

# Proxy ao nível stream: TCP + UDP 30120 → porta de jogo do FXServer
stream {
    upstream fivem_game {
        server <o-teu-ip-da-zaroz>:<a-tua-porta>;
    }
    server {
        listen 30120;
        proxy_pass fivem_game;
    }
    server {
        listen 30120 udp reuseport;
        proxy_pass fivem_game;
    }
}

Com este proxy à frente, o server.cfg fica:

sv_forceIndirectListing true
sv_listingHostOverride  "https://myserver.example.com/"
sv_endpoints            "<o-teu-ip-do-proxy>:30120"
sv_proxyIPRanges        "<o-teu-ip-do-proxy>/32"

Duas notas sobre este montagem avançada:

  • Não podes reaproveitar o subdomínio gerido pela Zaroz (por ex. myserver.play.zaroz.cloud) para isto, porque esse registo A já aponta para o IP do teu contentor e somos nós quem o gere automaticamente. Usa um domínio teu (um domínio próprio, com o DNS alojado na Cloudflare ou onde for).
  • O sv_proxyIPRanges é obrigatório, senão o FXServer rejeita o cabeçalho X-Real-IP que o proxy mete, e ainda por cima continua a aplicar o rate limiter por IP contra o único IP do teu proxy, o que rebenta depressa.

Erros típicos

  • Esquecer o esquema ou a porta no sv_listingHostOverride. Pôr sv_listingHostOverride "myserver.play.zaroz.cloud" (só o host) faz com que o backend tente http://myserver.play.zaroz.cloud:30120/ independentemente da porta que a tua encomenda usa, e isso falha. Usa sempre a forma URL completa, com esquema e porta corretos.
  • Não pôr sv_forceIndirectListing true. Sem isto, o teu IP continua a escapar na lista mesmo com o override posto, porque o backend trata o sv_listingHostOverride como valor puramente interno e continua a anunciar o IP cru aos clientes.
  • Achar que os registos SRV resolvem o navegador de servidores. Os SRV só afetam o comando connect na F8. O navegador de servidores passa pelo backend de listagem, que só respeita sv_listingHostOverride e sv_forceIndirectListing.
  • Propagação de DNS. A Cloudflare propaga depressa (tipicamente em menos de um minuto), mas o backend de listagem da cfx.re tem a sua própria cache. Conta uns minutos depois de qualquer alteração de configuração antes do novo connectEndPoints aparecer na API pública de servidores.

Quando nos contactar

Se seguiste o guia e:

  • Os endpoints (/info.json, /dynamic.json, /players.json) respondem no browser, e
  • No navegador de servidores o teu servidor continua a aparecer com o IP cru, ou
  • O connectEndPoints em https://servers.fivem.net/api/servers/single/<cfx-id> volta sempre ao IP depois de reiniciares,

envia-nos o teu server.cfg (com rcon_password e sv_licenseKey tapados), o ID de cfx.re do teu servidor e o número da tua encomenda. Verificamos se o backend de listagem nos está mesmo a chegar e confirmamos que do nosso lado nada está a pisar o teu override.