TeamSpeak 3 en Docker — migrer un serveur vocal standalone vers Docker Compose
TeamSpeak 3 en Docker — migration serveur vocal avec 235 Go de fichiers
Huitième étape : migrer TeamSpeak 3.13.7 (235 Go de fichiers transférés, base SQLite,
licence payante) depuis une installation standalone vers Docker Compose sur le serveur
centralisé, avec transfert progressif rsync.
Contexte
Le serveur TeamSpeak 3 tourne actuellement sur l’ancien serveur dédié
(54.36.51.208, ns3109491) 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 235 Go
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 (141.95.154.67, ns3210379,
SSH port 38592), où tournent déjà Odoo 17, Odoo 8, Akeneo PIM et ownCloud.
Architecture cible : 1 seul conteneur —
teamspeak:3.13.7 avec les 3 ports TeamSpeak exposés directement
(pas de reverse proxy, TeamSpeak n’est pas une application web).
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 235 Go 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
|
1 2 3 4 5 |
# Version /home/teamspeak3/ts3server version # Processus en cours ps aux | grep ts3 |
Résultat attendu : TeamSpeak 3 Server 3.13.7 (2022-06-20 12:21:53).
1.2 Ports utilisés
|
1 |
ss -tlnup | grep -E '9987|10011|30033|8767|10044|30034' |
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 |
cat /home/teamspeak3/ts3server.ini |
1.4 Taille des données
|
1 2 3 4 5 |
# Base de données SQLite ls -lh /home/teamspeak3/ts3server.sqlitedb # Fichiers transférés (icônes, avatars, fichiers de channels) sudo du -sh /home/teamspeak3/files/ |
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 : 235 Go dans
/home/teamspeak3/files/ - Licence : payante (
licensekey.dat) - Identité serveur :
serverkey.dat - Ports actifs : UDP
9987(voix), TCP10011(query), TCP30033(transfert fichiers) - 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.dat— identité cryptographique du serveur.
Sans ce fichier, le serveur apparaît comme un NOUVEAU serveur pour tous les clients.
Les favoris/bookmarks ne fonctionnent pluslicensekey.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 (235 Go)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 :
|
1 2 |
mkdir -p /home/docker/teamspeak3/data mkdir -p /home/docker/teamspeak3/backup |
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
|
1 |
nano /home/docker/teamspeak3/docker-compose.yml |
Contenu :
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
services: teamspeak: image: teamspeak:3.13.7 container_name: teamspeak3-server restart: always ports: - "9987:9987/udp" - "30033:30033" - "127.0.0.1:10011:10011" environment: TS3SERVER_LICENSE: accept volumes: - ./data:/var/ts3server networks: - teamspeak-network networks: teamspeak-network: name: teamspeak-network |
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ées9987:9987/udp— port voix, exposé en UDP sur toutes les interfaces
(les clients s’y connectent directement, pas de reverse proxy)30033:30033— port transfert de fichiers, exposé en TCP127.0.0.1:10011:10011— port ServerQuery, restreint à localhost
par sécurité (accès administration uniquement depuis le serveur)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 (235 Go),
la licence et l’identité serveur
Pas de serveradmin_password dans le docker-compose.
L’ancien serveur passait serveradmin_password=teamspeak2many 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) restreint à localhost :
le ServerQuery donne un accès administrateur complet au serveur TeamSpeak.
Ne jamais l’exposer sur Internet sans protection. L’ancien serveur avait déjà
une whitelist limitée à 127.0.0.1 et ::1.
En plus de cette whitelist, on restreint le port Docker à localhost.
4) Lancer le rsync initial (en arrière-plan)
Cette étape est la plus longue (plusieurs heures pour 235 Go).
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 :
|
1 2 3 |
# Si pas encore fait pour les migrations précédentes ssh-keygen -t ed25519 -C "migration-teamspeak" ssh-copy-id -p 38596 root@54.36.51.208 |
4.2 Lancer le premier rsync
Depuis le nouveau serveur :
|
1 2 3 4 5 6 7 8 9 10 |
# Lancer dans un screen pour ne pas perdre le transfert screen -S rsync-teamspeak # Rsync initial : copie complète des fichiers transférés (235 Go) rsync -avt --progress -e "ssh -p 38596" \ root@54.36.51.208:/home/teamspeak3/files/ \ /home/docker/teamspeak3/data/files/ # Détacher le screen : Ctrl+A puis D # Rattacher plus tard : screen -r rsync-teamspeak |
Estimation de durée : entre serveurs OVH (réseau interne ~1 Gbps),
235 Go 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
|
1 2 3 4 5 6 |
# Sur l'ancien serveur sudo systemctl stop teamspeak3 # Vérifier qu'il est bien arrêté sudo systemctl status teamspeak3 ps aux | grep ts3 |
Prévenir les utilisateurs avant l’arrêt.
On peut envoyer un message global depuis ServerQuery avant la coupure :
|
1 2 3 |
# Optionnel : prévenir les utilisateurs connectés # (depuis l'ancien serveur, avant l'arrêt) echo -e "login serveradmin teamspeak2many\nuse sid=1\nsendtextmessage targetmode=3 target=1 msg=Maintenance\\sen\\scours\\s-\\smigration\\sdu\\sserveur.\\sReconnexion\\sdans\\s10\\sminutes." | nc 127.0.0.1 10011 |
6) Rsync final + fichiers critiques
Depuis le nouveau serveur :
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
# Rsync final des fichiers (delta uniquement, très rapide) rsync -avt --delete --progress -e "ssh -p 38596" \ root@54.36.51.208:/home/teamspeak3/files/ \ /home/docker/teamspeak3/data/files/ # Copier la base de données SQLite rsync -avt -e "ssh -p 38596" root@54.36.51.208:/home/teamspeak3/ts3server.sqlitedb \ /home/docker/teamspeak3/data/ # Copier les fichiers critiques (identité, licence, clés) rsync -avt -e "ssh -p 38596" root@54.36.51.208:/home/teamspeak3/serverkey.dat \ /home/docker/teamspeak3/data/ rsync -avt -e "ssh -p 38596" root@54.36.51.208:/home/teamspeak3/licensekey.dat \ /home/docker/teamspeak3/data/ rsync -avt -e "ssh -p 38596" root@54.36.51.208:/home/teamspeak3/ssh_host_rsa_key \ /home/docker/teamspeak3/data/ rsync -avt -e "ssh -p 38596" root@54.36.51.208:/home/teamspeak3/query_ip_whitelist.txt \ /home/docker/teamspeak3/data/ |
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
|
1 2 |
ls -la /home/docker/teamspeak3/data/ ls -la /home/docker/teamspeak3/data/files/ | head -10 |
On doit voir :
ts3server.sqlitedb(~4,5 Mo)serverkey.dat(112 octets)licensekey.dat(~1,6 Ko)ssh_host_rsa_keyquery_ip_whitelist.txtfiles/(répertoire avec les sous-dossiersvirtualserver_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
|
1 2 |
# Démarrer temporairement le conteneur pour vérifier l'UID docker run --rm teamspeak:3.13.7 id |
Noter le uid affiché (typiquement 1000).
7.2 Appliquer les permissions
|
1 2 |
# Adapter l'UID si différent de 1000 chown -R 1000:1000 /home/docker/teamspeak3/data/ |
Cette commande prend du temps sur 235 Go 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
|
1 2 3 4 5 6 7 8 |
# Port voix (UDP) /usr/local/vesta/bin/v-add-firewall-rule ACCEPT 0.0.0.0/0 9987 UDP "TeamSpeak Voice" # Port transfert de fichiers (TCP) /usr/local/vesta/bin/v-add-firewall-rule ACCEPT 0.0.0.0/0 30033 TCP "TeamSpeak File Transfer" # Appliquer les règles /usr/local/vesta/bin/v-update-firewall |
Ces commandes sont l’équivalent CLI de MyVestaCP → Firewall → Add 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
|
1 2 |
# Vérifier les règles iptables générées par MyVestaCP iptables -L INPUT -n | grep -E '9987|30033' |
On doit voir :
|
1 2 |
ACCEPT udp -- 0.0.0.0/0 0.0.0.0/0 udp dpt:9987 ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:30033 |
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
|
1 2 |
cd /home/docker/teamspeak3/ docker compose up -d |
Vérifier l’état du conteneur :
|
1 |
docker compose ps |
Le conteneur doit être en état Up.
Consulter les logs :
|
1 |
docker compose logs teamspeak |
On doit voir :
|
1 2 3 4 5 6 |
TeamSpeak 3 Server 3.13.7 Using SQLite database plugin Listening on 0.0.0.0:9987, [::]:9987 FileTransfer listener listening on 0.0.0.0:30033, [::]:30033 ServerQuery listener listening on 0.0.0.0:10011, [::]:10011 Server started |
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
|
1 2 |
# Depuis le serveur (localhost) echo "version" | nc 127.0.0.1 10011 |
Réponse attendue :
|
1 2 3 4 |
TS3 Welcome to the TeamSpeak 3 ServerQuery interface... version=3.13.7 build=... platform=Linux error id=0 msg=ok |
10.2 Tester la connectivité UDP (voix)
|
1 2 |
# Depuis une machine externe nc -zuv 141.95.154.67 9987 |
Doit afficher Connection to 141.95.154.67 9987 port [udp/*] succeeded!
(ou open).
10.3 Se connecter avec le client TeamSpeak
Ouvrir le client TeamSpeak 3 et se connecter à 141.95.154.67 (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
|
1 2 |
# Vérifier que la licence est bien chargée echo -e "login serveradmin teamspeak2many\nserverinfo" | nc 127.0.0.1 10011 | grep -i licen |
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) Désactiver l’ancien serveur
Une fois la migration validée, empêcher l’ancien serveur de redémarrer :
|
1 2 3 |
# Sur l'ancien serveur sudo systemctl disable teamspeak3 sudo systemctl stop teamspeak3 |
Pas de bascule DNS pour TeamSpeak.
Les clients se connectent par IP (pas par domaine).
Il faudra mettre à jour les bookmarks/favoris des utilisateurs
avec la nouvelle IP 141.95.154.67.
Alternativement, configurer un enregistrement DNS
(ex : ts.mcdtoolbox.com) pointant vers la nouvelle IP
pour faciliter les futures migrations.
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 :
|
1 2 3 4 5 |
# Vérifier que la base est présente dans le bon répertoire ls -la /home/docker/teamspeak3/data/ts3server.sqlitedb # Vérifier les permissions (doit appartenir à l'UID du conteneur) docker compose exec teamspeak ls -la /var/ts3server/ts3server.sqlitedb |
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 :
|
1 2 |
ls -la /home/docker/teamspeak3/data/licensekey.dat docker compose exec teamspeak ls -la /var/ts3server/licensekey.dat |
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 :
|
1 2 3 4 5 |
# Vérifier que le port est bien ouvert ss -ulnp | grep 9987 # Vérifier le firewall iptables -L INPUT -n | grep 9987 |
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.
|
1 2 3 4 5 6 |
# Vérifier que le port 30033 est ouvert ss -tlnp | grep 30033 iptables -L INPUT -n | grep 30033 # Vérifier les permissions du répertoire files docker compose exec teamspeak ls -la /var/ts3server/files/ |
Erreur database is locked dans les logs
Vérifier qu’il n’y a pas de fichiers -shm ou -wal résiduels :
|
1 |
ls -la /home/docker/teamspeak3/data/ts3server.sqlitedb* |
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).
Identité serveur différente (clients affichent un warning)
Le client affiche « Server identity changed » à la connexion.
|
1 |
ls -la /home/docker/teamspeak3/data/serverkey.dat |
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
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
Nouveau serveur (141.95.154.67) ┌────────────────────────────────────────────────────────────────────────────────────────┐ │ │ │ Docker : /home/docker/teamspeak3/ │ │ ┌───────────────────────────────────────────────────────────────────────────┐ │ │ │ teamspeak3-server (teamspeak:3.13.7) │ │ │ │ UDP :9987 → voix (clients se connectent directement) │ │ │ │ TCP :30033 → transfert de fichiers │ │ │ │ TCP :10011 → ServerQuery (localhost seulement) │ │ │ │ bind: ./data → /var/ts3server (SQLite + 235 Go files + licence) │ │ │ └───────────────────────────────────────────────────────────────────────────┘ │ │ │ │ Aussi sur ce serveur (via reverse proxy MyVestaCP) : │ │ Odoo 17 (:8069-8369), Odoo 8 (:8469), Akeneo PIM (:8480), ownCloud (:8490) │ └────────────────────────────────────────────────────────────────────────────────────────┘ |
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)9987/udp— TeamSpeak 3 voix (direct, pas de proxy)10011/tcp— TeamSpeak 3 ServerQuery (localhost seulement)30033/tcp— TeamSpeak 3 transfert de fichiers (direct)
Astuce : créer un enregistrement DNS pour TeamSpeak
Pour éviter que les utilisateurs doivent mettre à jour leurs bookmarks
à chaque migration, créer un enregistrement DNS :
- Type : A
- Nom : ts (ou vocal, teamspeak, etc.)
- Valeur :
141.95.154.67
Les utilisateurs se connectent alors à ts.mcdtoolbox.com.
Lors de la prochaine migration, il suffit de changer l’IP dans le DNS
sans toucher aux bookmarks des clients.
SRV record pour port personnalisé :
si le port n’est pas le défaut (9987), créer un enregistrement SRV :
_ts3._udp.mcdtoolbox.com 0 5 9987 ts.mcdtoolbox.com.
Avec le port 9987 (standard), l’enregistrement A suffit.
À suivre
TeamSpeak 3 est maintenant opérationnel en Docker.
Dans les prochains articles :
- Autres serveurs de jeux (Counter-Strike 1.6, EmuLinker)
- Sauvegardes automatisées et stratégie de rétention
- Monitoring et alertes
0 commentaire