TeamSpeak 3 en Docker — migrer un serveur vocal standalone vers Docker Compose

Published by David on






TeamSpeak 3 en Docker — migration serveur vocal avec {{TAILLE_DONNEES}} de fichiers

TeamSpeak 3 en Docker — migration serveur vocal avec {{TAILLE_DONNEES}} de fichiers

Huitième étape : migrer TeamSpeak 3.13.7 ({{TAILLE_DONNEES}} de fichiers transférés, base SQLite,
licence payante) depuis une installation standalone vers Docker Compose sur le serveur
centralisé, avec transfert progressif rsync.

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_TS}} Domaine TeamSpeak exemple-gaming.fr
{{SERVERQUERY_PASSWORD}} Mot de passe admin ServerQuery MyS3cur3P@ss!
{{USER_VESTA}} Utilisateur MyVestaCP admin
{{TAILLE_DONNEES}} Taille des fichiers transférés 50 Go
{{TAILLE_DONNEES_PRECEDENT}} Taille données article précédent 100 Go

Contexte

Le serveur TeamSpeak 3 tourne actuellement sur l’ancien serveur dédié
({{IP_ANCIEN}}, {{HOSTNAME_ANCIEN}}) sous le chemin /home/teamspeak3/,
en tant qu’utilisateur système teamspeak3 via un service systemd.

Il utilise une base SQLite (~4,5 Mo), stocke {{TAILLE_DONNEES}}
de fichiers transférés par les utilisateurs (icônes, avatars, fichiers de channels),
et possède une licence payante (licensekey.dat).
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 et ownCloud.

Architecture cible : 2 conteneurs —
teamspeak:3.13.7 (serveur vocal, ports exposés directement)
et joni1802/ts3-manager (interface web d’administration via reverse proxy Nginx).

Différence clé avec les applications web :
contrairement à Odoo, Akeneo ou ownCloud, TeamSpeak n’utilise pas
de reverse proxy Nginx. Les clients se connectent directement via UDP (voix)
et TCP (transfert de fichiers, query). Les ports doivent donc être ouverts
dans le firewall du serveur.

Stratégie rsync 2 passes : avec {{TAILLE_DONNEES}} de fichiers sur HDD,
un transfert complet prend plusieurs heures. On fait un premier rsync pendant
que l’ancien serveur est encore en production
(aucune interruption du vocal),
puis un second rsync rapide (delta seulement) après l’arrêt du serveur.
Fenêtre de coupure réduite à quelques minutes au lieu de plusieurs heures.


1) Collecter les informations sur l’ancien serveur

1.1 Version et processus

Résultat attendu : TeamSpeak 3 Server 3.13.7 (2022-06-20 12:21:53).

1.2 Ports utilisés

Vérifier les ports réels : le fichier ts3server.ini
de notre serveur contient des ports personnalisés (8767, 10044,
30034), mais le serveur écoute en réalité sur les ports standards
(9987, 10011, 30033).
Cette incohérence peut venir du fait que le fichier ini n’est pas chargé
ou que la base de données prévaut sur la configuration ini pour les serveurs virtuels existants.
Vérifier avec ss quels ports sont réellement utilisés
et les noter — ce sont ceux que les clients TeamSpeak utilisent.

1.3 Contenu du fichier de configuration

1.4 Taille des données

Résumé de notre installation :

  • Version : TeamSpeak 3 Server 3.13.7
  • Base de données : SQLite (ts3server.sqlitedb, ~4,5 Mo)
  • Fichiers transférés : {{TAILLE_DONNEES}} dans /home/teamspeak3/files/
  • Licence : payante (licensekey.dat)
  • Identité serveur : serverkey.dat
  • Ports actifs : UDP 9987 + 9988 (voix, 2 serveurs virtuels), TCP 10011 (query), TCP 30033 (transfert fichiers)
  • Domaine : {{DOMAINE_TS}} (port 9988)
  • Utilisateur système : teamspeak3
  • Service systemd : teamspeak3.service

1.5 Fichiers critiques à préserver

  • ts3server.sqlitedb — la base de données complète (utilisateurs, channels, permissions, bans, tokens)
  • serverkey.datidentité cryptographique du serveur.
    Sans ce fichier, le serveur apparaît comme un NOUVEAU serveur pour tous les clients.
    Les favoris/bookmarks ne fonctionnent plus
  • licensekey.dat — licence payante TeamSpeak. Sans elle, le serveur repasse en licence gratuite (limité à 32 slots)
  • ssh_host_rsa_key — clé SSH pour les connexions ServerQuery via SSH (optionnel mais pratique)
  • files/ — tous les fichiers transférés dans les channels ({{TAILLE_DONNEES}})
  • query_ip_whitelist.txt — IPs autorisées pour ServerQuery

serverkey.dat est irremplaçable. Il contient la clé privée
qui génère l’identité unique du serveur. Si ce fichier est perdu, le serveur
aura une nouvelle identité et tous les clients recevront un avertissement
« Server identity changed » et devront re-valider la connexion.
Les bookmarks avec « Connect only to known servers » refuseront de se connecter.


Phase 1 : Préparation (ancien serveur en production)

Toutes les étapes suivantes se font sans interrompre le serveur vocal.
Les utilisateurs continuent à parler normalement.

2) Créer la structure des répertoires Docker

Sur le nouveau serveur :

Docker Compose v2 : si Docker Compose v2 est déjà installé (vérifier avec
docker compose version), pas besoin de le réinstaller.

3) Créer le docker-compose.yml

Contenu :

Points clés :

  • teamspeak:3.13.7 — image Docker officielle TeamSpeak, même version que l’ancien serveur
    pour éviter les problèmes de compatibilité de base de données
  • 9987:9987/udp — port voix du serveur virtuel 1, exposé en UDP sur toutes les interfaces
  • 9988:9988/udp — port voix du serveur virtuel 2 ({{DOMAINE_TS}}:9988)
  • 30033:30033 — port transfert de fichiers, exposé en TCP
  • 10011:10011 — port ServerQuery, exposé sur toutes les interfaces
    pour permettre le monitoring LGSL depuis l’hôte. Protégé par la whitelist
    TeamSpeak (query_ip_whitelist.txt) et le firewall VestaCP
  • TS3SERVER_LICENSE: accept — acceptation automatique de la licence (obligatoire depuis TS 3.1.0)
  • ./data:/var/ts3server — bind mount pour la base SQLite, les fichiers transférés ({{TAILLE_DONNEES}}),
    la licence et l’identité serveur

TS3 Manager :

  • joni1802/ts3-manager — interface web d’administration TeamSpeak (ts3.app)
  • 127.0.0.1:8080:8080 — port web restreint à localhost, accès via reverse proxy Nginx
  • WHITELIST — autorise les connexions ServerQuery vers le conteneur teamspeak
    (nom DNS Docker) et l’IP du serveur hôte
  • teamspeak-network — réseau Docker partagé permettant à TS3 Manager
    d’atteindre le port ServerQuery (10011) du conteneur TeamSpeak par son nom de service

Pas de serveradmin_password dans le docker-compose.
L’ancien serveur passait serveradmin_password={{SERVERQUERY_PASSWORD}} en paramètre de démarrage,
ce qui réinitialise le mot de passe admin à chaque redémarrage.
Après migration, le mot de passe est stocké dans la base SQLite importée.
Il n’est plus nécessaire (ni souhaitable) de le passer en paramètre —
il serait visible dans la liste des processus (ps aux).

Port ServerQuery (10011) exposé sur toutes les interfaces :
le port 10011 est ouvert pour permettre le monitoring LGSL depuis le serveur hôte
(PHP tourne sur l’IP publique, pas sur 127.0.0.1). La sécurité est assurée par :
(1) la whitelist TeamSpeak (query_ip_whitelist.txt limitée à 127.0.0.1,
::1 et {{IP_NOUVEAU}}),
(2) le firewall VestaCP qui ne laisse pas passer le port 10011 depuis l’extérieur.
Ne jamais ouvrir le port 10011 dans le firewall.

4) Lancer le rsync initial (en arrière-plan)

Cette étape est la plus longue (plusieurs heures pour {{TAILLE_DONNEES}}).
On la lance pendant que l’ancien serveur est encore en production
les utilisateurs continuent à utiliser le vocal normalement.

4.1 Préparer l’accès SSH

Depuis le nouveau serveur :

4.2 Lancer le premier rsync

Depuis le nouveau serveur :

Estimation de durée : entre serveurs OVH (réseau interne ~1 Gbps),
{{TAILLE_DONNEES}} prennent environ 1h à 2h30.
Le flag -t préserve les timestamps des fichiers.

Pas de risque de corruption : les fichiers dans files/
sont des fichiers statiques (uploads des utilisateurs dans les channels).
Ils ne sont jamais modifiés après l’upload, seulement ajoutés ou supprimés.
Le rsync pendant que le serveur tourne est donc sans risque.


Phase 2 : Basculement (fenêtre de coupure)

À partir d’ici, le serveur vocal est interrompu.
Objectif : terminer en 5 à 10 minutes
(la base SQLite fait seulement 4,5 Mo, le rsync delta est très rapide).

5) Arrêter TeamSpeak sur l’ancien serveur

Prévenir les utilisateurs avant l’arrêt.
On peut envoyer un message global depuis ServerQuery avant la coupure :

6) Rsync final + fichiers critiques

Depuis le nouveau serveur :

Arrêter le serveur AVANT de copier la base SQLite.
Les fichiers ts3server.sqlitedb-shm et ts3server.sqlitedb-wal
(shared memory + write-ahead log) contiennent des données non encore écrites dans le fichier
principal. Copier la base pendant que le serveur tourne peut donner une base corrompue.
Après l’arrêt propre (systemctl stop), le WAL est flushé dans le fichier principal.

Ne PAS copier les fichiers -shm et -wal :
après un arrêt propre du serveur, ces fichiers sont vides ou inexistants.
Le fichier ts3server.sqlitedb seul est suffisant.

6.1 Vérifier les fichiers copiés

On doit voir :

  • ts3server.sqlitedb (~4,5 Mo)
  • serverkey.dat (112 octets)
  • licensekey.dat (~1,6 Ko)
  • ssh_host_rsa_key
  • query_ip_whitelist.txt
  • files/ (répertoire avec les sous-dossiers virtualserver_1/, etc.)

7) Corriger les permissions

L’image Docker officielle teamspeak s’exécute en tant qu’utilisateur
ts3server. Il faut que tous les fichiers lui appartiennent.

7.1 Déterminer l’UID du conteneur

Noter le uid affiché (typiquement 1000).

7.2 Appliquer les permissions

Cette commande prend du temps sur {{TAILLE_DONNEES}} de fichiers (5-15 minutes sur HDD).
C’est une opération unique.

8) Ouvrir les ports dans le firewall

Contrairement aux applications web (routées via le reverse proxy Nginx de MyVestaCP),
TeamSpeak a besoin que ses ports soient ouverts directement dans le firewall du serveur.

8.1 Ajouter les règles dans MyVestaCP

Ces commandes sont l’équivalent CLI de MyVestaCP → FirewallAdd Rule.
Les règles sont stockées dans /usr/local/vesta/data/firewall/
et persistent après un redémarrage.

8.2 Vérifier que les règles sont actives

On doit voir :

Port 10011 (ServerQuery) : pas besoin de l’ouvrir dans le firewall.
Il est déjà restreint à 127.0.0.1 dans le docker-compose
et dans la whitelist TeamSpeak. L’administration se fait uniquement depuis le serveur.

Ne pas ajouter les règles via iptables directement.
MyVestaCP stocke ses règles dans /usr/local/vesta/data/firewall/
et les régénère via v-update-firewall.
Toute règle ajoutée manuellement sera perdue au prochain redémarrage de VestaCP
ou lors d’un v-update-firewall.

9) Démarrer TeamSpeak

Vérifier l’état du conteneur :

Le conteneur doit être en état Up.

Consulter les logs :

On doit voir :

Si le serveur affiche « Server created » au lieu de « Server started »,
cela signifie que la base de données n’a pas été trouvée et le serveur a créé
une nouvelle instance vierge. Vérifier que ts3server.sqlitedb est bien
dans /home/docker/teamspeak3/data/ et que les permissions sont correctes.

10) Tester

10.1 Tester le ServerQuery

Réponse attendue :

10.2 Tester la connectivité UDP (voix)

Doit afficher Connection to {{IP_NOUVEAU}} 9987 port [udp/*] succeeded!
(ou open).

10.3 Se connecter avec le client TeamSpeak

Ouvrir le client TeamSpeak 3 et se connecter à {{IP_NOUVEAU}} (port par défaut 9987).
Vérifier :

  • Les channels sont présents avec leur hiérarchie
  • Les permissions et groupes de serveur sont intacts
  • Les icônes de channels et de groupes s’affichent
  • Les fichiers dans les channels sont accessibles (onglet « Files »)
  • Le micro et le son fonctionnent

10.4 Vérifier la licence

Si la licence n’est pas détectée, le serveur sera limité à 32 slots.
Vérifier que licensekey.dat est bien dans /home/docker/teamspeak3/data/.

11) Mettre un serveur TeamSpeak de migration sur l’ancien serveur

Rediriger les utilisateurs vers la nouvelle IP.
Avant de couper l’ancien serveur, il est recommandé de lancer un serveur TeamSpeak
temporaire (« trash ») sur l’ancienne IP ({{IP_ANCIEN}})
qui affiche un message de migration indiquant la nouvelle IP.
Ainsi, les utilisateurs qui se connectent encore à l’ancienne adresse
voient immédiatement où aller.

En mode gratuit (sans licence), TeamSpeak limite à 1 serveur virtuel
et 32 slots par instance. Pour couvrir les deux ports (9987 et 9988),
il faut lancer deux instances séparées du binaire ts3server,
chacune avec sa propre base de données, ses propres ports et son propre utilisateur système.

Pourquoi deux utilisateurs système ?
TeamSpeak utilise un fichier de verrouillage dans /dev/shm/ pour empêcher
de lancer deux instances sans licence sur la même machine. Le paramètre
machine_id ne suffit pas à contourner ce verrou dans la version 3.13.7.
La solution : isoler le /dev/shm de la seconde instance via
TemporaryFileSystem=/dev/shm dans le service systemd.

12) Désactiver l’ancien serveur

Une fois la migration validée, empêcher l’ancien serveur de redémarrer :

Bascule DNS : mettre à jour l’enregistrement A de {{DOMAINE_TS}}
pour qu’il pointe vers {{IP_NOUVEAU}} (au lieu de l’ancien serveur).
Les clients qui se connectent via {{DOMAINE_TS}}:9988 seront automatiquement redirigés.

13) TS3 Manager — interface web d’administration

TS3 Manager (v2.2.5) est une interface web légère
pour administrer TeamSpeak 3 via le protocole ServerQuery. Il permet de gérer
les utilisateurs, channels, permissions, bans et groupes depuis un navigateur.
L’application est stateless (pas de base de données propre).

13.1 Prérequis

  • Le service ts3-manager est déjà défini dans le docker-compose.yml (section 3)
  • Un sous-domaine (ex. ts3.{{DOMAINE_TS}}) avec enregistrement DNS A vers {{IP_NOUVEAU}}

13.2 Créer le template Nginx reverse proxy dans VestaCP

TS3 Manager utilise des WebSockets. On crée un template réutilisable pour
tout reverse proxy sur le port 8080 :

13.3 Créer le domaine et appliquer le template

13.4 Se connecter à TS3 Manager

Accéder à https://ts3.{{DOMAINE_TS}} et renseigner :

  • Server : teamspeak (nom du service Docker, pas l’IP)
  • Port : 10011
  • SSH : décoché (ServerQuery utilise telnet)
  • Name : serveradmin
  • Password : le mot de passe serveradmin (stocké dans la base SQLite)

TS3 Manager se connecte via le réseau Docker interne (teamspeak-network).
Il utilise le nom de service teamspeak pour atteindre le port 10011 du conteneur,
sans passer par le réseau de l’hôte. C’est pourquoi le champ Server est teamspeak
et non 127.0.0.1 ou l’IP publique.


Dépannage

Le serveur crée une nouvelle instance au lieu de charger l’ancienne

Les logs affichent « Server created » et un nouveau token admin est généré.

Diagnostiquer :

Cause : la base SQLite n’est pas au bon emplacement
ou n’est pas lisible par l’utilisateur du conteneur.
Corriger les permissions : chown 1000:1000 /home/docker/teamspeak3/data/ts3server.sqlitedb.

Licence non détectée (limité à 32 slots)

Vérifier que licensekey.dat est dans le répertoire de données :

Si le fichier est présent mais la licence n’est pas chargée, vérifier
les logs pour des erreurs de lecture. Redémarrer le conteneur après avoir
corrigé les permissions.

Impossible de se connecter en UDP (voix)

Diagnostiquer :

Cause fréquente : le firewall bloque le port UDP 9987.
Ajouter la règle (section 8) et vérifier qu’elle n’est pas écrasée par MyVestaCP.

Transfert de fichiers échoue

Les fichiers ne se téléchargent pas ou ne s’uploadent pas.

Erreur database is locked dans les logs

Vérifier qu’il n’y a pas de fichiers -shm ou -wal résiduels :

Si les fichiers -shm et -wal existent et sont non vides,
la base a été copiée pendant que le serveur tournait encore.
Recopié la base après arrêt propre du serveur (section 6).

Perte de données après docker compose run

NE JAMAIS utiliser docker compose run avec TeamSpeak.
Cette commande crée un conteneur éphémère avec un volume temporaire.
TeamSpeak détecte l’absence de base de données et en crée une nouvelle,
écrasant potentiellement les données existantes (serveurs virtuels, channels, permissions).

Exemple de commande à ne pas faire :

Pour modifier la configuration de TeamSpeak, toujours utiliser docker compose exec
qui s’exécute dans le conteneur existant :

En cas de perte de données, restaurer ts3server.sqlitedb depuis une sauvegarde,
arrêter le conteneur, remplacer la base, corriger les permissions
(chown 1000:1000) et redémarrer.

Identité serveur différente (clients affichent un warning)

Le client affiche « Server identity changed » à la connexion.

Cause : serverkey.dat est manquant ou différent.
Le serveur a généré une nouvelle identité au premier démarrage.
Arrêter le conteneur, remplacer serverkey.dat par celui de l’ancien serveur,
et redémarrer.


Récapitulatif de l’architecture finale

Ports utilisés sur le serveur :

  • 8069-8369 — Odoo 17 (4 instances, via reverse proxy)
  • 8469 — Odoo 8 (via reverse proxy)
  • 8480 — Akeneo PIM 7 (via reverse proxy)
  • 8490 — ownCloud 10 (via reverse proxy)
  • 8080 — TS3 Manager (127.0.0.1, via reverse proxy → ts3.{{DOMAINE_TS}})
  • 9987/udp — TeamSpeak 3 voix, serveur virtuel 1 (direct)
  • 9988/udp — TeamSpeak 3 voix, serveur virtuel 2 (direct)
  • 10011/tcp — TeamSpeak 3 ServerQuery (whitelist + firewall, utilisé par LGSL et TS3 Manager)
  • 30033/tcp — TeamSpeak 3 transfert de fichiers (direct)

Mettre à jour le DNS de {{DOMAINE_TS}}

Le domaine {{DOMAINE_TS}} pointe actuellement vers l’ancien serveur.
Mettre à jour l’enregistrement A pour pointer vers la nouvelle IP :

  • Type : A
  • Nom : @ (racine)
  • Valeur : {{IP_NOUVEAU}}

Les clients se connectent à {{DOMAINE_TS}}:9988.
Après propagation DNS, ils atteindront automatiquement le nouveau serveur.

SRV record (optionnel) :
pour éviter que les clients doivent spécifier le port 9988 manuellement,
créer un enregistrement SRV :
_ts3._udp.{{DOMAINE_TS}} 0 5 9988 {{DOMAINE_TS}}.
Le client TeamSpeak résoudra automatiquement le bon port.


À suivre

TeamSpeak 3 est maintenant opérationnel en Docker avec TS3 Manager
pour l’administration web et LGSL pour le monitoring.
Dans les prochains articles :

  • Serveurs de jeux Counter-Strike 1.6 (Pterodactyl Panel)
  • LGSL — monitoring des serveurs de jeux et TeamSpeak
  • Sauvegardes automatisées et stratégie de rétention

Article précédent : ownCloud 10 en Docker — migration {{TAILLE_DONNEES_PRECEDENT}} avec rsync progressif.



Catégories : Non classé

0 commentaire

Laisser un commentaire

Emplacement de l’avatar

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *