Afficher ton domaine personnalisé dans le navigateur de serveurs FiveM¶
Ce guide explique, de A à Z, comment faire pour que ton domaine perso (par ex. play.example.com) apparaisse dans le navigateur de serveurs intégré à FiveM quand les joueurs cherchent ton serveur, et comment faire en sorte que connect play.example.com marche depuis la console F8.
On va couvrir :
- Ce que Zaroz Cloud met en place automatiquement quand tu rattaches un domaine à ta commande.
- Les lignes supplémentaires à mettre dans
server.cfgpour que le domaine apparaisse vraiment dans la liste (à la place de l'IP brute). - Comment fonctionne sous le capot le backend de listing cfx.re, pour pouvoir débugger quand quelque chose coince.
- Le setup avancé (ton propre reverse proxy) si tu veux masquer totalement l'IP pour la protection DDoS.
Comment un domaine perso arrive jusqu'à la liste de serveurs¶
Avant de toucher à la moindre config, il faut le modèle mental. FiveM fait deux choses totalement différentes, par deux chemins de code totalement différents :
-
Rejoindre le serveur en tapant
connect <nom>dans la console F8. Cette voie passe par le DNS. Le client cherche un enregistrement SRV (_cfx._udp.<ton-domaine>) pour trouver le port, puis un enregistrement A pour trouver l'IP, et il se connecte. Il ne demande jamais rien au backend de listing cfx.re. -
Trouver (ou rejoindre) le serveur via le navigateur ingame. Cette voie passe par le backend de listing cfx.re. Le backend pingue périodiquement ton serveur sur une URL du style
https://<host>/dynamic.jsonpour rafraîchir les données de la liste. Quand un joueur clique « Connect » dans le navigateur, le backend renvoie au client un champconnectEndPointsqui lui dit où il doit réellement se connecter. C'est ceconnectEndPointsqui détermine si le joueur voit ton IP ou ton domaine.
Les deux voies sont indépendantes : les enregistrements SRV font marcher la commande connect, mais ils n'ont aucun effet sur ce que montre le navigateur ingame. Pour piloter le navigateur, il faut dire à ton propre serveur quel domaine annoncer au backend de listing.
Les règles officielles sur la façon dont un client résout une cible de connexion sont résumées dans la doc proxy de Cfx.re :
- Les hôtes nus (par ex.
play.example.com) deviennenthttp://play.example.com:30120/. - Les hôtes avec port (par ex.
play.example.com:30121) deviennenthttp://play.example.com:30121/. - Les URLs avec schéma (par ex.
https://play.example.com/) sont prises telles quelles, avec les ports par défaut du schéma (80/443).
Cette dernière règle est la plus importante pour la liste : si tu veux que la liste donne aux joueurs une URL propre https://play.example.com/ (sans port, sans schéma à taper), le backend de listing doit pouvoir atteindre ton serveur exactement à cette URL.
Ce que Zaroz Cloud fait pour toi¶
Quand tu rattaches un domaine à ta commande depuis le tableau de bord (Page commande → onglet External Access → Custom domain) :
- On prend le parent domain choisi (par ex.
play.zaroz.cloud) et le sous-domaine que tu as tapé (par ex.myserver), ce qui donne le nom completmyserver.play.zaroz.cloud. - Via Cloudflare, on crée un enregistrement A pour ce nom, pointant vers l'IP publique que ta commande s'est vu attribuer.
- Pour les commandes FiveM, on crée aussi un enregistrement SRV dans
_cfx._udp.<ton-host>qui repointe vers le même nom avec le port UDP de jeu de ta commande. (Sur Minecraft c'est_minecraft._tcp.<host>, sur Factorio_factorio._udp.<host>.) - Un job de réconciliation en tâche de fond garde les deux enregistrements synchronisés si ta commande est déplacée vers un autre node ou si son port est réassigné.
Effet net : dès que le domaine est rattaché, les joueurs peuvent déjà rejoindre avec connect myserver.play.zaroz.cloud depuis la console F8, même sans port. Le SRV indique au client FiveM le port UDP, et le A donne l'IP.
Ce que ça ne fait pas tout seul : ça ne change pas ce que montre le navigateur de serveurs ingame. Pour ça, il faut bien modifier server.cfg.
Setup minimal server.cfg pour le navigateur de serveurs¶
Si tu te contentes du flux connect basé sur SRV (taper l'adresse dans la console F8), tu n'as pas besoin de toucher à server.cfg. Les enregistrements qu'on crée suffisent.
Si tu veux que le navigateur de serveurs affiche ton domaine quand les joueurs cherchent ton serveur, ajoute ces lignes en haut de server.cfg :
# Fait comme si tu n'avais pas d'IP statique. Force le backend à utiliser
# connectEndPoints/sv_listingHostOverride au lieu de laisser fuiter l'IP.
sv_forceIndirectListing true
# Dit au backend quel host interroger, et quel host renvoyer au joueur
# dans le bouton « Connect ».
sv_listingHostOverride "http://myserver.play.zaroz.cloud:30120/"
Utilise la forme URL complète, pas juste le nom d'hôte :
- Le schéma (
http://) dit au backend que ton serveur parle du HTTP simple, pas du HTTPS. Le endpoint par défaut de FXServer est en HTTP, pas en HTTPS. - Le port (
:30120) est le vrai port jeu/HTTP de ton conteneur. Si tu l'omets, le backend suppose le port 80, sur lequel FXServer n'écoute pas, et le heartbeat échoue.
Sur Zaroz Cloud, ton <port> est la valeur que tu vois en haut de server.cfg, dans la ligne endpoint_add_tcp "0.0.0.0:<port>" que notre entrypoint réécrit à chaque démarrage du conteneur. Tu peux aussi le lire directement depuis le tableau de bord, sous Page commande → External Access → Player connection :

La partie après les deux-points dans Server address est le port à mettre dans sv_listingHostOverride.
Après un redémarrage, le master devrait prendre en compte l'override en quelques minutes et commencer à annoncer ton nom d'hôte dans la liste. Voir la section « Comment vérifier que ça a marché » plus bas.
À quoi sert chaque ligne¶
sv_forceIndirectListing true¶
D'après la doc officielle : "prevents the server list from advertising your server using its actual IP" (empêche la liste d'annoncer ton serveur avec sa vraie IP).
Si c'est désactivé, la liste continue de publier l'IP brute peu importe ce que dit sv_listingHostOverride, parce que le backend suppose que n'importe quel client peut se connecter directement à l'IP source et que l'override ne sert qu'en interne pour le heartbeat. Avec ça activé, l'IP est masquée et le champ connectEndPoints porte le nom d'hôte à la place.
sv_listingHostOverride¶
D'après la doc officielle : "makes the server list backend request https://server1.example.com/ instead of the default" (fait taper le backend sur https://server1.example.com/ au lieu de l'adresse par défaut).
Cette convar joue deux rôles à la fois :
- Où le backend te pingue. Le heartbeat cfx.re tape
<host>/dynamic.json,<host>/info.jsonet<host>/players.jsonà cette URL. - Ce que voient les joueurs / où ils se connectent. Quand le listing indirect est activé, cette même valeur est renvoyée aux clients dans
connectEndPoints, ce qui pilote le bouton « Connect » du navigateur.
À cause de ce double rôle, la valeur doit être joignable depuis internet. Sur Zaroz, l'endpoint HTTP de ton conteneur est lié à 0.0.0.0:<ton-port> et ton enregistrement A pointe déjà le nom d'hôte vers la bonne IP, donc http://<host>:<port>/ marche sans infrastructure supplémentaire.
Et sv_listingIpOverride alors ?¶
Normalement, tu n'as pas besoin de le toucher sur Zaroz Cloud. D'après la doc officielle : "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" (cette valeur n'est utile que si le backend ne peut pas deviner seul l'IP à interroger, et n'est jamais transmise aux connexions clients).
Notre entrypoint écrit déjà le bon sv_listingIpOverride pour l'IP publique qu'on t'a attribuée, à chaque démarrage du conteneur. C'est l'IP que le master utilise pour trouver ton dynamic.json quand il n'y a pas de host override. Avec sv_listingHostOverride posé, l'override IP devient redondant mais inoffensif.
Et sv_endpoints alors ?¶
sv_endpoints c'est "the actual endpoint your server is hosted on, or one or multiple server endpoint proxies" (l'endpoint réel où tourne ton serveur, ou un ou plusieurs proxies d'endpoint).
Dans un setup vanilla sans proxy, tu n'en as pas besoin : le backend de listing va utiliser l'IP qu'il pingue et le port qu'il découvre. On ne le pose que si tu mets ton propre reverse proxy ou tunnel DDoS entre les joueurs et FXServer, et qu'il faut dire aux joueurs de se connecter à l'IP/port du proxy, pas à ceux de FXServer.
Enregistrements DNS, en entier¶
Si tu veux vérifier côté Cloudflare ce qu'on a posé, voilà à quoi ressemble un domaine perso Zaroz qui marche :
;; Enregistrement A
myserver.play.zaroz.cloud. 60 IN A 188.213.7.49
;; Enregistrement SRV (FiveM)
_cfx._udp.myserver.play.zaroz.cloud. 60 IN SRV 0 0 32541 myserver.play.zaroz.cloud.
Champs, dans l'ordre : priorité (0), poids (0), port (le port UDP de jeu de ta commande, par ex. 32541), cible (ton nom d'hôte, terminé par un point).
L'IP et le port sont des exemples ; ils reflètent ce que le kernel avait attribué à ta commande au moment de créer l'enregistrement. Si ta commande est déplacée sur un autre node ou son port réassigné, le job de réconciliation réécrit les deux enregistrements.
Comment vérifier que ça a marché¶
Après avoir redémarré le serveur avec le nouveau server.cfg, tu peux contrôler de trois façons.
1. Taper sur les endpoints depuis le navigateur¶
Ceux-ci doivent tous renvoyer du JSON (ou au moins un HTTP 200) :
http://<ton-domaine>:<ton-port>/info.jsonhttp://<ton-domaine>:<ton-port>/players.jsonhttp://<ton-domaine>:<ton-port>/dynamic.json
Si l'un d'eux part en timeout ou renvoie une erreur de connexion, le master non plus n'y arrive pas. Vérifie le pare-feu et que l'URL dans sv_listingHostOverride correspond à ce que ton conteneur écoute vraiment.
2. Regarder la console du serveur¶
Après le boot, cherche les lignes de log de [citizen-server-impl]. Un serveur en bonne santé finit par logger des heartbeats réussis. Si tu vois Server list query returned an error: server request failed for endpoint http://<host>:<port>/dynamic.json, c'est que le master a tenté de joindre l'override et a échoué ; la cause la plus fréquente (retard de cache de license key) est expliquée dans le guide d'erreur Server list query.
3. Interroger l'API servers publique¶
Va sur https://servers.fivem.net/api/servers/single/<ton-cfx-id> (l'ID cfx est la courte chaîne alphanumérique dans l'URL de ton listing ingame) et regarde le champ connectEndPoints dans le JSON. Une fois ton override propagé, il doit contenir ton domaine, pas l'IP brute.
Avancé : avec ton propre reverse proxy¶
Le setup de base ci-dessus cache ton IP de la liste de serveurs, mais un attaquant déterminé peut toujours la retrouver en envoyant les bons paquets directement au port jeu. Si tu veux masquer entièrement l'IP (par exemple, derrière un tunnel Cloudflare Spectrum ou ton propre nginx sur une IP séparée), il te faut un vrai reverse proxy.
Layout de référence, adapté de la doc proxy officielle et du gist nginx de la communauté :
# Proxy couche HTTP : 443 → HTTP port jeu de FXServer
upstream fivem_http {
server <ton-ip-zaroz>:<ton-port>;
}
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 couche stream : TCP + UDP 30120 → port jeu de FXServer
stream {
upstream fivem_game {
server <ton-ip-zaroz>:<ton-port>;
}
server {
listen 30120;
proxy_pass fivem_game;
}
server {
listen 30120 udp reuseport;
proxy_pass fivem_game;
}
}
Avec ce proxy en place, le server.cfg devient :
sv_forceIndirectListing true
sv_listingHostOverride "https://myserver.example.com/"
sv_endpoints "<ton-ip-proxy>:30120"
sv_proxyIPRanges "<ton-ip-proxy>/32"
Deux remarques sur ce setup avancé :
- Tu ne peux pas réutiliser le sous-domaine géré par Zaroz (par ex.
myserver.play.zaroz.cloud), parce que son enregistrement A pointe déjà vers l'IP de ton conteneur et qu'on le gère automatiquement. Prends un domaine que tu possèdes (un domaine perso, avec le DNS hébergé sur Cloudflare ou ailleurs). sv_proxyIPRangesest obligatoire, sinon FXServer rejette le headerX-Real-IPque le proxy pose, et le rate limiter par IP tape toujours sur l'unique IP du proxy, qui sature vite.
Pièges classiques¶
- Oublier le schéma ou le port dans
sv_listingHostOverride. Mettresv_listingHostOverride "myserver.play.zaroz.cloud"(juste le nom) fait que le backend tentehttp://myserver.play.zaroz.cloud:30120/peu importe le port réellement utilisé par ta commande, et ça échoue. Utilise toujours la forme URL complète avec le bon schéma et le bon port. - Ne pas activer
sv_forceIndirectListing true. Sans ça, ton IP continue de fuiter dans la liste malgré l'override, parce que le backend traitesv_listingHostOverridecomme une valeur purement interne et continue d'annoncer l'IP brute aux clients. - Croire que les enregistrements SRV règlent le navigateur de serveurs. Les SRV n'agissent que sur la commande
connecten F8. Le navigateur de serveurs passe par le backend de listing, qui ne respecte quesv_listingHostOverrideetsv_forceIndirectListing. - Propagation DNS. Cloudflare propage vite (typiquement moins d'une minute), mais le backend de listing cfx.re a son propre cache. Compte quelques minutes après tout changement de config avant que le nouveau
connectEndPointsapparaisse dans l'API servers publique.
Quand nous écrire¶
Si tu as suivi ce guide et que :
- Les endpoints (
/info.json,/dynamic.json,/players.json) sont joignables depuis un navigateur, et - Ton serveur ingame affiche encore l'IP brute, ou
- Le
connectEndPointsdanshttps://servers.fivem.net/api/servers/single/<cfx-id>revient sans cesse à l'IP après un redémarrage,
envoie-nous ta server.cfg (avec rcon_password et sv_licenseKey masqués), l'ID cfx.re de ton serveur, et ton numéro de commande. On vérifie si le backend de listing arrive bien jusqu'à nous et qu'il n'y a rien de notre côté qui écrase ton override.