Migrer un serveur EmuLinker Kaillera vers Docker Compose avec network_mode host
EmuLinker en Docker — migration serveur Kaillera vers Docker Compose
Neuvième étape : migrer EmuLinker (serveur Kaillera pour le jeu rétro en ligne)
depuis une installation Java standalone vers Docker Compose, avec conservation de la
configuration et des sessions.
Paramètres à personnaliser
Remplacez chaque {{VARIABLE}} par vos propres valeurs avant d’utiliser ce guide.
| Variable | Description | Exemple |
|---|---|---|
{{IP_ANCIEN}} |
IP du serveur source | 203.0.113.10 |
{{IP_NOUVEAU}} |
IP du serveur cible | 198.51.100.20 |
{{HOSTNAME_ANCIEN}} |
Hostname de l’ancien serveur | ns1234567 |
{{HOSTNAME_NOUVEAU}} |
Hostname du nouveau serveur | ns7654321 |
{{PORT_SSH_ANCIEN}} |
Port SSH de l’ancien serveur | 22222 |
{{PORT_SSH_NOUVEAU}} |
Port SSH du nouveau serveur | 22223 |
{{DOMAINE_GAMING}} |
Domaine gaming | exemple-gaming.fr |
{{NOM_SERVEUR_KAILLERA}} |
Nom affiché dans la master list | Mon Serveur Kaillera - Europe |
{{TAILLE_DONNEES_PRECEDENT}} |
Taille données article précédent | 50 Go |
Contexte
EmuLinker est un serveur Kaillera pour le jeu rétro en ligne. Le protocole Kaillera
permet aux joueurs de jouer à des jeux multijoueur locaux via Internet en utilisant
des émulateurs comme MAME, Project64, ePSXe, ZSNES, Snes9k, et bien d’autres.
Contrairement à d’autres protocoles de jeu en ligne, Kaillera synchronise les entrées
des joueurs en temps réel pour simuler une session de jeu local.
Actuellement, EmuLinker (version originale, classe org.emulinker.kaillera.pico.PicoStarter)
tourne comme un processus Java 11 (OpenJDK 11.0.30) sur l’ancien serveur
dédié ({{IP_ANCIEN}}, {{HOSTNAME_ANCIEN}}) dans /home/emulinker/,
lancé via systemd (emulinker.service).
On migre vers Docker Compose sur le nouveau serveur ({{IP_NOUVEAU}}, {{HOSTNAME_NOUVEAU}},
SSH port {{PORT_SSH_NOUVEAU}}), où tournent déjà Odoo 17, Odoo 8, Akeneo PIM, ownCloud et TeamSpeak 3.
Architecture cible : 1 conteneur Docker (OpenJDK + jar EmuLinker) en mode
network_mode: host pour optimiser la latence UDP.
Les serveurs de jeux Kaillera utilisent plus de 70 ports UDP dynamiques (27886-27944 + 54715-54730).
Le NAT Docker ajoute de la latence sur chaque paquet UDP, ce qui dégrade l’expérience de jeu.
En mode host, le conteneur partage directement le réseau de l’hôte, éliminant cette surcharge.
Domaine : {{DOMAINE_GAMING}}.
1) Identifier l’installation existante
Première étape : se connecter à l’ancien serveur et identifier la version d’EmuLinker,
la version Java, la structure des fichiers, et le mode de lancement.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
ssh -p {{PORT_SSH_ANCIEN}} root@{{IP_ANCIEN}} # Lister le contenu du répertoire EmuLinker ls -la /home/emulinker/ # Identifier la version Java utilisée java -version # Trouver le jar EmuLinker find /home/emulinker/ -name "*.jar" -type f # Vérifier le service systemd (si existant) systemctl status emulinker 2>/dev/null || systemctl list-units | grep -i emu # Vérifier si lancé via screen screen -ls # Vérifier les ports écoutés ss -tulnp | grep -E '27888|27886' # Lire la configuration cat /home/emulinker/conf/emulinker.cfg 2>/dev/null || \ find /home/emulinker/ -name "*.cfg" -o -name "*.conf" -o -name "*.properties" | head -20 |
Notre installation : c’est l’EmuLinker original (pas un fork K, SF ou X).
Le serveur est lancé avec un classpath complexe incluant 13 jars de dépendances
dans lib/, et la configuration est dans emulinker.cfg à la racine
(pas dans conf/). Le répertoire conf/ est inclus dans le classpath
pour access.cfg et la configuration log4j.
1.1 Résumé de l’installation
Résumé de notre installation :
- Version : EmuLinker original (
org.emulinker.kaillera.pico.PicoStarter) - Runtime : OpenJDK 11.0.30 (image Docker :
eclipse-temurin:11-jre) - JVM :
-Xms64m -Xmx128m - Configuration principale :
emulinker.cfg(à la racine, pas dansconf/) - Configuration accès :
conf/access.cfg - Lancement : classpath complexe avec 13 jars dans
lib/ - Service :
emulinker.service(systemd, enabled) - Port principal : 27888 (Kaillera standard)
- Ports jeux : 27886-27944 (UDP dynamique)
- Ports P2P : 54715-54730 (UDP peer-to-peer)
- Domaine :
{{DOMAINE_GAMING}} - Nom serveur :
{{NOM_SERVEUR_KAILLERA}} - Utilisateur système :
emulinker - Répertoire :
/home/emulinker/ - Max joueurs : 100
1.2 Fichiers critiques à préserver
lib/emulinker.jar+ 13 jars de dépendances danslib/
(commons-collections, commons-configuration, commons-lang, commons-logging,
dom4j, log4j, picocontainer, etc.)emulinker.cfg— configuration principale du serveur (nom, ports,
master list, limites de connexion, messages)conf/access.cfg— règles d’accès et permissionsconf/log4j.xml— configuration des logs (si présent dans le classpath)wordlist.txt,questions.txt— listes pour les mini-jeux intégrésscores.txt,scores_scrambler.txt— scores des joueurslaunch.sh— script de lancement (pour référence, remplacé par Docker)
2) Créer la structure des répertoires Docker
Sur le nouveau serveur :
|
1 2 |
mkdir -p /home/docker/emulinker/server mkdir -p /home/docker/emulinker/backup |
server/— contiendra tous les fichiers EmuLinker (jar, configuration, logs)backup/— pour stocker les sauvegardes avant migration
3) Transférer les fichiers depuis l’ancien serveur
Depuis le nouveau serveur :
|
1 2 3 4 |
# Copier tout le répertoire EmuLinker rsync -avz --progress -e "ssh -p {{PORT_SSH_ANCIEN}}" \ root@{{IP_ANCIEN}}:/home/emulinker/ \ /home/docker/emulinker/server/ |
EmuLinker est extrêmement léger comparé à TeamSpeak (quelques Mo contre {{TAILLE_DONNEES_PRECEDENT}}).
Le transfert devrait prendre quelques secondes seulement.
4) Créer le docker-compose.yml
|
1 |
nano /home/docker/emulinker/docker-compose.yml |
Contenu :
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
services: emulinker: image: eclipse-temurin:11-jre container_name: emulinker-server restart: always network_mode: host working_dir: /opt/emulinker command: - java - -Xms64m - -Xmx128m - -cp - "./conf:./lib/*" - org.emulinker.kaillera.pico.PicoStarter volumes: - ./server:/opt/emulinker |
Points clés :
eclipse-temurin:11-jre— correspond à l’OpenJDK 11 utilisé sur l’ancien serveurnetwork_mode: host— le conteneur partage directement le réseau de l’hôte,
pas de NAT Docker. Optimal pour les serveurs de jeux avec beaucoup de ports UDPcommand— reproduit le classpath complexe dulaunch.shoriginal :
le répertoireconf/+ tous les jars danslib/via le wildcard./lib/*./server:/opt/emulinker— tout le répertoire EmuLinker monté dans le conteneur
Classpath Java : EmuLinker ne se lance pas avec un simple java -jar.
Il nécessite un classpath qui inclut conf/ (pour access.cfg et log4j)
et les 13 jars de lib/. Le wildcard ./lib/* fonctionne avec Java 6+
et évite de lister chaque jar individuellement (comme le faisait le launch.sh original).
La classe principale est org.emulinker.kaillera.pico.PicoStarter.
Mode réseau host : network_mode: host signifie que le conteneur
partage directement le réseau de l’hôte. Pas besoin de mapper les ports individuellement
— tous les ports sur lesquels EmuLinker écoute sont directement accessibles.
C’est le choix optimal pour les serveurs de jeux avec beaucoup de ports UDP
(27886-27944 + 54715-54730 = plus de 70 ports), car le NAT Docker ajoute de la latence
sur les paquets UDP, ce qui dégrade l’expérience de jeu.
5) Adapter la configuration EmuLinker
Après le transfert, certains paramètres de configuration doivent être mis à jour
pour refléter le nouveau serveur.
|
1 2 |
# La configuration principale est à la racine (pas dans conf/) nano /home/docker/emulinker/server/emulinker.cfg |
Modification obligatoire — adresse IP du serveur :
|
1 2 3 4 5 6 |
# Remplacer l'ancienne IP par la nouvelle # Ligne actuelle : masterList.serverConnectAddress={{IP_ANCIEN}} # Remplacer par : masterList.serverConnectAddress={{IP_NOUVEAU}} |
Critique : si masterList.serverConnectAddress n’est pas mis à jour,
les serveurs master list Kaillera continueront de pointer les joueurs vers l’ancienne IP.
Le serveur apparaîtra dans la liste publique mais les connexions échoueront.
Autres paramètres à vérifier (normalement OK sans modification) :
masterList.serverName={{NOM_SERVEUR_KAILLERA}}— nom affiché dans la liste publiquemasterList.serverWebsite=http://{{DOMAINE_GAMING}}— site web du serveurserver.port=27888— port principal Kaillera (ne pas changer)server.maxUsers=100— limite de joueurs simultanésserver.maxGames=50— limite de parties simultanées
Configuration accès : le fichier conf/access.cfg contient les règles
d’accès (bans, admins, etc.). Il est transféré automatiquement avec le rsync de l’étape 3
et ne nécessite normalement aucune modification.
Serveurs master list Kaillera : les IPs 216.189.101.117 et
50.203.71.60 sont les serveurs master list Kaillera historiques
(anti3d.com et kaillera.com). Ils permettent aux joueurs de trouver votre serveur
dans la liste publique des clients Kaillera. Si votre serveur est privé
(connexion directe par IP/domaine), ces règles firewall ne sont pas strictement nécessaires.
6) Vérifier les règles firewall
Les règles firewall sont déjà configurées sur le nouveau serveur via MyVestaCP.
Vérifions qu’elles sont bien en place :
|
1 2 |
# Vérifier les règles iptables iptables -L INPUT -n | grep -E '27888|27886|27944|54715|80' |
Résultat attendu :
|
1 2 3 4 5 |
ACCEPT tcp -- 216.189.101.117 0.0.0.0/0 tcp dpt:80 ACCEPT tcp -- 50.203.71.60 0.0.0.0/0 tcp dpt:80 ACCEPT udp -- 0.0.0.0/0 0.0.0.0/0 udp dpts:27888:27944 ACCEPT udp -- 0.0.0.0/0 0.0.0.0/0 udp dpts:27886:27887 ACCEPT udp -- 0.0.0.0/0 0.0.0.0/0 udp dpts:54715:54730 |
Explication des règles :
- Emulinker-Master-List / Master-List-2 — TCP port 80 restreint aux IPs
des serveurs master list Kaillera (216.189.101.117 et 50.203.71.60). Permet à ces serveurs
de vérifier que notre serveur est en ligne et de l’afficher dans la liste publique - Emulinker-Classic-Kaillera — UDP 27888 (port principal) + 27889-27944
(ports de jeu dynamiques) — ouverts à tous pour que les joueurs puissent se connecter - Emulinker-p2p — UDP 27886-27887 + 54715-54730 — ports pour le mode
peer-to-peer, permettant le jeu direct entre joueurs sans transiter par le serveur
Règles déjà en place : les règles firewall sont déjà en place
sur le nouveau serveur. Si ce n’est pas le cas, les ajouter via MyVestaCP CLI :
|
1 2 3 4 5 6 7 8 9 10 11 12 |
# Ports Kaillera classiques (UDP) /usr/local/vesta/bin/v-add-firewall-rule ACCEPT 0.0.0.0/0 27888 UDP Emulinker-Kaillera-Main /usr/local/vesta/bin/v-add-firewall-rule ACCEPT 0.0.0.0/0 27889:27944 UDP Emulinker-Kaillera-Games /usr/local/vesta/bin/v-add-firewall-rule ACCEPT 0.0.0.0/0 27886:27887 UDP Emulinker-P2P /usr/local/vesta/bin/v-add-firewall-rule ACCEPT 0.0.0.0/0 54715:54730 UDP Emulinker-P2P-Extended # Master list (TCP) - restreint aux IPs des serveurs master list /usr/local/vesta/bin/v-add-firewall-rule ACCEPT 216.189.101.117 80 TCP Emulinker-Master-List-2 /usr/local/vesta/bin/v-add-firewall-rule ACCEPT 50.203.71.60 80 TCP Emulinker-Master-List # Appliquer /usr/local/vesta/bin/v-update-firewall |
Format des commentaires MyVestaCP : les commentaires ne doivent pas contenir
d’espaces. Utiliser des tirets (Emulinker-Kaillera-Main) au lieu d’espaces
(Emulinker Kaillera Main), sinon l’erreur
Error: invalid comment format apparaît.
7) Arrêter l’ancien serveur
Avant de démarrer le nouveau serveur Docker, arrêter l’ancien pour éviter
les conflits de port et de master list :
|
1 2 3 4 5 6 7 8 9 10 11 |
# Sur l'ancien serveur ssh -p {{PORT_SSH_ANCIEN}} root@{{IP_ANCIEN}} # Arrêter le service systemd systemctl stop emulinker.service # Désactiver le démarrage automatique systemctl disable emulinker.service # Vérifier que le port est libéré ss -tulnp | grep 27888 |
Si la dernière commande ne retourne rien, le port est bien libéré.
8) Démarrer EmuLinker en Docker
Retour sur le nouveau serveur :
|
1 2 |
cd /home/docker/emulinker/ docker compose up -d |
Vérifier que le conteneur est en cours d’exécution :
|
1 2 |
docker compose ps docker compose logs --tail=50 |
Vérifier que le port 27888 est bien en écoute :
|
1 |
ss -tulnp | grep 27888 |
Résultat attendu :
|
1 |
udp UNCONN 0 0 0.0.0.0:27888 0.0.0.0:* |
Redémarrage en boucle : si le conteneur redémarre en boucle,
vérifier les logs : docker compose logs --tail=100.
Les causes les plus fréquentes sont : mauvais nom de jar dans command,
version Java incompatible, ou fichier de configuration manquant.
9) Tester la connexion
Tester que les ports sont bien accessibles depuis l’extérieur :
|
1 2 3 |
# Vérifier que les ports sont ouverts depuis l'extérieur # (depuis une autre machine) nc -uzv {{IP_NOUVEAU}} 27888 |
Test avec un client Kaillera :
- Ouvrir un émulateur compatible Kaillera (MAME, Project64, ePSXe avec plugin Kaillera, ZSNES, Snes9k, etc.)
- Dans le client Kaillera, ajouter le serveur manuellement :
{{IP_NOUVEAU}}:27888 - Ou une fois le DNS mis à jour :
{{DOMAINE_GAMING}}:27888 - Vérifier que le serveur apparaît et que la connexion fonctionne
- Tenter de créer une salle de jeu et de démarrer une partie pour valider le fonctionnement complet
Master list publique : si le serveur est enregistré sur la master list Kaillera,
il devrait apparaître automatiquement dans la liste publique du client après quelques minutes
(une fois que les serveurs master list ont détecté le nouveau serveur).
10) Désactiver définitivement l’ancien serveur
Une fois la migration validée :
|
1 2 3 4 |
# Sur l'ancien serveur (si pas déjà fait) ssh -p {{PORT_SSH_ANCIEN}} root@{{IP_ANCIEN}} systemctl stop emulinker.service systemctl disable emulinker.service |
DNS partagé : le domaine {{DOMAINE_GAMING}} est partagé entre
TeamSpeak (port 9988) et EmuLinker (port 27888). Si l’enregistrement A a déjà été
mis à jour pour TeamSpeak (vers {{IP_NOUVEAU}}), EmuLinker en bénéficie
automatiquement. Les joueurs pourront se connecter via {{DOMAINE_GAMING}}:27888.
Dépannage
EmuLinker ne démarre pas : « ClassNotFoundException » ou « NoClassDefFoundError »
Cause : le classpath dans command ne trouve pas les classes nécessaires.
|
1 2 3 4 5 6 7 8 9 10 11 12 |
# Vérifier que les jars sont bien présents ls /home/docker/emulinker/server/lib/*.jar # Vérifier que le répertoire conf/ existe ls /home/docker/emulinker/server/conf/ # Vérifier les logs Docker pour l'erreur exacte docker compose logs --tail=50 # Redémarrer après correction docker compose down docker compose up -d |
EmuLinker ne démarre pas : « UnsupportedClassVersionError »
Cause : la version Java dans l’image Docker ne correspond pas.
Notre installation utilise Java 11 (eclipse-temurin:11-jre).
|
1 2 3 4 5 6 |
# Vérifier que l'image est bien eclipse-temurin:11-jre dans docker-compose.yml grep "image:" /home/docker/emulinker/docker-compose.yml # Redémarrer après correction docker compose down docker compose up -d |
Le serveur n’apparaît pas dans la master list
Causes possibles :
- Les règles firewall TCP port 80 pour les IPs master list ne sont pas actives
- La configuration EmuLinker ne contient pas les bonnes URLs de master list
- Les serveurs master list Kaillera sont hors ligne (ce sont des infrastructures anciennes, parfois instables)
|
1 2 3 4 5 6 7 8 9 10 11 12 |
# Vérifier les règles firewall iptables -L INPUT -n | grep -E '216.189.101.117|50.203.71.60' # Vérifier la configuration EmuLinker (fichier à la racine, pas dans conf/) grep -i "master" /home/docker/emulinker/server/emulinker.cfg # Vérifier que l'IP est bien la nouvelle grep "serverConnectAddress" /home/docker/emulinker/server/emulinker.cfg # Tester manuellement la connexion aux master lists curl -I http://216.189.101.117/ curl -I http://50.203.71.60/ |
Les joueurs ne peuvent pas se connecter
|
1 2 3 4 5 6 7 8 9 10 11 |
# Vérifier les règles firewall iptables -L INPUT -n | grep 27888 # Vérifier que le port est en écoute ss -tulnp | grep 27888 # Vérifier que Docker tourne docker compose ps # Vérifier les logs docker compose logs --tail=100 |
Latence élevée en jeu
Causes possibles :
- Le mode
network_mode: hostn’est pas activé (le NAT Docker ajoute de la latence) - Le serveur est surchargé (CPU/RAM)
- Problème réseau entre les joueurs et le serveur
|
1 2 3 4 5 6 7 8 9 |
# Vérifier la configuration réseau dans docker-compose.yml grep "network_mode" /home/docker/emulinker/docker-compose.yml # Doit afficher : network_mode: host # Vérifier l'utilisation CPU/RAM docker stats emulinker-server # Tester la latence depuis un client ping {{IP_NOUVEAU}} |
Sensibilité à la latence : le protocole Kaillera est très sensible
à la latence. Le mode network_mode: host minimise la surcharge réseau
en évitant le NAT Docker. Si la latence reste élevée malgré cette configuration,
le problème vient probablement de la distance géographique entre les joueurs
ou de la qualité de leur connexion Internet.
Récapitulatif de l’architecture finale
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
Services Docker sur {{IP_NOUVEAU}} ({{HOSTNAME_NOUVEAU}}) ────────────────────────────────────────────── Applications web (via reverse proxy MyVestaCP) : ├── Odoo 17 → 127.0.0.1:8069/8169/8269/8369 ├── Odoo 8 → 127.0.0.1:8469 ├── Akeneo PIM → 127.0.0.1:8480 └── ownCloud → 127.0.0.1:8490 Serveurs de jeux (ports exposés directement) : ├── TeamSpeak 3 → 9987/udp, 9988/udp, 30033/tcp └── EmuLinker → 27888/udp (+ 27886-27944, 54715-54730) Domaine {{DOMAINE_GAMING}} : ├── TeamSpeak 3 → :9988 (serveur virtuel 2) └── EmuLinker → :27888 (Kaillera) |
Liste complète des ports utilisés :
8069/8169/8269/8369— Odoo 17 (via reverse proxy)8469— Odoo 8 (via reverse proxy)8480— Akeneo PIM (via reverse proxy)8490— ownCloud (via reverse proxy)9987/udp+9988/udp— TeamSpeak 3 voix (direct)10011/tcp— TeamSpeak 3 ServerQuery (localhost seulement)30033/tcp— TeamSpeak 3 transfert fichiers (direct)27886-27944/udp— EmuLinker Kaillera (direct, host network)54715-54730/udp— EmuLinker P2P (direct, host network)
À suivre
EmuLinker est maintenant opérationnel en Docker avec une configuration optimisée
pour la latence minimale (mode host network).
Dans les prochains articles :
- Counter-Strike 1.6 en Docker — migration du serveur de jeu CS 1.6
- Sauvegardes automatisées — stratégie de backup pour tous les services Docker
- Monitoring et alertes — surveillance centralisée des conteneurs
0 commentaire