Après avoir construit et validé mon site Homelab en local, l’étape suivante était logique : le mettre réellement en production sur mon VPS.
Je ne voulais pas simplement copier quelques fichiers sur un serveur. L’objectif était de conserver une architecture claire, reproductible et cohérente avec le reste de mon Homelab : Docker, Nginx Proxy Manager, réseaux séparés, volumes persistants, sauvegardes et possibilité de revenir en arrière en cas de problème.
Cette migration a donc été réalisée comme une vraie petite opération de production : sauvegarder, transférer, restaurer, tester, basculer le domaine, sécuriser puis nettoyer.

Le point de départ : un WordPress validé en local
Mon environnement local comportait déjà une version fonctionnelle du site avec :
- WordPress ;
- MariaDB ;
- mon thème personnalisé NVSD Homelab 2.1.2 ;
- les articles et médias ;
- une mise en page alignée sur le builder ;
- une stack Docker reproductible.
Je voulais conserver cette installation locale comme environnement de développement et de test.
Le principe retenu est donc simple :
LOCAL
Développement / tests / évolution du thème
↓ migration contrôlée
VPS
Version de production publique
Cette séparation me permet de continuer à faire évoluer le thème ou les contenus sans expérimenter directement sur la version publique.
Étape 1 — Sauvegarder avant de migrer
Avant de modifier quoi que ce soit sur le VPS, j’ai créé une sauvegarde complète de la version locale.
Elle contenait notamment :
database.sql
wordpress-files.tar.gz
theme-nvsd-homelab.tar.gz
compose.yaml
theme-version.txt
SHA256SUMS
La base MariaDB a été exportée avec mariadb-dump. Les fichiers WordPress ont été archivés séparément et le thème a également reçu sa propre archive.
J’ai ensuite généré des sommes SHA256 pour pouvoir vérifier que les fichiers transférés n’avaient pas été altérés.
sha256sum database.sql \
wordpress-files.tar.gz \
theme-nvsd-homelab.tar.gz \
> SHA256SUMS
Ce contrôle peut sembler excessif pour un simple site WordPress, mais il devient vite utile dès qu’un Homelab héberge plusieurs services. Une migration doit pouvoir être interrompue et recommencée sans perdre l’état de départ.


Étape 2 — Organiser la stack sur le VPS
J’ai profité de la migration pour uniformiser l’organisation de mon serveur.
Toutes les stacks sont désormais regroupées sous :
/opt/homelab/stacks/
La nouvelle stack WordPress se trouve dans :
/opt/homelab/stacks/nvsd-homelab-wordpress/
avec une structure volontairement simple :
nvsd-homelab-wordpress/
├── compose.yaml
├── .env
├── theme/
│ └── nvsd-homelab/
├── restore/
└── backup/
Cette convention est importante pour moi : chaque projet possède un dossier identifiable, son Compose, ses ressources et ses sauvegardes.
Étape 3 — Séparer les réseaux Docker

Je ne voulais surtout pas publier MariaDB directement sur le VPS.
La stack utilise donc deux réseaux Docker.
Le premier est privé :
nvsd_homelab_internal
Il relie uniquement WordPress à MariaDB.
Le second est le réseau partagé :
proxy
Il permet à Nginx Proxy Manager d’atteindre WordPress.
L’architecture finale est donc :
Internet
↓
HTTPS
↓
Nginx Proxy Manager
↓
réseau Docker proxy
↓
WordPress :80
↓
réseau Docker privé
↓
MariaDB :3306
MariaDB n’est jamais exposée directement à Internet, et WordPress ne possède pas non plus de port public une fois la migration terminée.

Étape 4 — Restaurer MariaDB avant WordPress
J’ai commencé par démarrer uniquement la base de données.
Une fois MariaDB en état healthy, j’ai importé le dump SQL provenant de l’environnement local.
Pour vérifier rapidement que la restauration était correcte, j’ai interrogé WordPress directement dans la base :
SELECT COUNT(*) AS articles
FROM wp_posts
WHERE post_type='post';
Le résultat retournait bien mes 7 articles.
À ce stade, les données étaient restaurées, mais il restait encore à remettre les médias, plugins et fichiers spécifiques au site.
Étape 5 — Restaurer wp-content sans écraser inutilement le cœur WordPress
Plutôt que de remplacer aveuglément tout /var/www/html, j’ai laissé l’image officielle WordPress initialiser son propre cœur applicatif.
J’ai ensuite restauré le contenu spécifique du site, principalement :
wp-content/
Ce dossier contient notamment :
- les médias ;
- les plugins ;
- les données propres au site.
Le thème NVSD est monté séparément depuis l’hôte en lecture seule :
./theme/nvsd-homelab
↓
/var/www/html/wp-content/themes/nvsd-homelab
Ainsi, le thème stocké dans la stack reste ma source de référence.
Après restauration, le dossier uploads représentait environ 18 Mo, ce qui confirmait que les médias avaient bien été récupérés.
Étape 6 — Comprendre le premier 301
Le premier test HTTP sur le VPS a retourné :
HTTP/1.1 301 Moved Permanently
Location: http://127.0.0.1:8086/
Ce n’était pas une erreur de Docker, Apache ou Nginx Proxy Manager.
La base WordPress contenait encore les valeurs de l’environnement local :
home = http://127.0.0.1:8086
siteurl = http://127.0.0.1:8086
WordPress faisait donc exactement ce qu’on lui demandait.
Avant de changer ces URL, j’ai utilisé un tunnel SSH pour vérifier visuellement le WordPress restauré sur le VPS tout en conservant l’adresse locale attendue par la base.
Cette étape m’a permis de contrôler le thème, les images et les articles avant la bascule publique.
Étape 7 — Remplacer les URL avec WP-CLI
Une fois le rendu du VPS validé, j’ai remplacé l’ancienne URL locale par :
https://homelab.nvsd.ch
Pour cette opération, j’ai utilisé WP-CLI plutôt qu’un REPLACE() SQL brut.
WordPress peut stocker certaines données PHP sous forme sérialisée. Une modification SQL trop simple peut casser ces structures.
J’ai donc commencé par un test sans modification :
wp search-replace \
'http://127.0.0.1:8086' \
'https://homelab.nvsd.ch' \
--all-tables-with-prefix \
--precise \
--recurse-objects \
--skip-columns=guid \
--dry-run
Résultat :
Success: 23 replacements to be made.
Les remplacements concernaient notamment :
wp_options
wp_postmeta
wp_posts
wp_users
Le dry-run étant cohérent, j’ai exécuté le remplacement réel.
Les options principales sont alors devenues :
home = https://homelab.nvsd.ch
siteurl = https://homelab.nvsd.ch
Étape 8 — Basculer Nginx Proxy Manager
Le domaine homelab.nvsd.ch existait déjà dans Nginx Proxy Manager.
Je n’ai pas créé un nouveau Proxy Host. J’ai simplement modifié la cible du host existant :
Scheme : http
Forward Hostname : nvsd-homelab-wordpress
Forward Port : 80
Nginx Proxy Manager et WordPress sont tous deux connectés au réseau Docker proxy.
Ils communiquent donc directement par leur nom de conteneur, sans devoir publier un port WordPress sur l’hôte.
Le premier test public a retourné :
HTTP/1.1 200 OK
Server: openresty
X-Powered-By: PHP/8.3.31
X-Served-By: homelab.nvsd.ch
À ce moment, le WordPress du VPS était réellement devenu la version de production.
Étape 9 — Supprimer le port WordPress temporaire
Pendant les tests, WordPress utilisait encore temporairement un port publié sur le VPS.
Une fois Nginx Proxy Manager validé, ce port n’était plus nécessaire.
Après suppression du bloc ports: dans le Compose, WordPress n’affichait plus que :
80/tcp
et la commande :
docker port nvsd-homelab-wordpress
ne retournait plus rien.
C’est un point important : WordPress n’est plus directement exposé sur l’hôte. Le trafic public passe obligatoirement par le reverse proxy.
Étape 10 — Vérifier la chaîne complète
J’ai d’abord testé l’accès depuis le réseau Docker proxy :
docker run --rm \
--network proxy \
curlimages/curl:latest \
-I \
-H 'Host: homelab.nvsd.ch' \
-H 'X-Forwarded-Proto: https' \
http://nvsd-homelab-wordpress/
Résultat :
HTTP/1.1 200 OK
Puis depuis l’extérieur :
curl -IL https://homelab.nvsd.ch
Résultat :
HTTP/1.1 200 OK
La chaîne complète était donc validée :
Internet
↓
Nginx Proxy Manager
↓
WordPress
↓
MariaDB
Étape 11 — Créer une sauvegarde de la première version de production
Avant de commencer le nettoyage, j’ai créé une nouvelle sauvegarde de la version réellement mise en production.
Cette sauvegarde constitue maintenant un point de restauration clair comprenant :
- la base MariaDB ;
- les fichiers WordPress ;
- le thème NVSD Homelab 2.1.2 ;
- le
compose.yaml; - le
.envprotégé ; - les sommes SHA256 ;
- l’état des conteneurs, réseaux, volumes et images.
Je préfère toujours sauvegarder l’état validé avant de supprimer les ressources devenues inutiles.

Étape 12 — Nettoyer les anciens volumes Docker
Après la migration, quatre volumes WordPress existaient encore :
nvsd-homelab-wordpress_db_data
nvsd-homelab-wordpress_wordpress_data
nvsd_homelab_db_data
nvsd_homelab_wordpress_data
L’inspection des montages des conteneurs a confirmé que seuls :
nvsd_homelab_db_data
nvsd_homelab_wordpress_data
étaient réellement utilisés.
Les anciens volumes ont alors été supprimés.
État final :
Local Volumes : 2
Active : 2
Reclaimable : 0 B
Étape 13 — Nettoyer les réseaux devenus inutiles
Le VPS contenait également plusieurs réseaux créés par d’anciennes versions de stacks :
concerto-infini-phase9_default
dockge_default
nvsd_nvsd-net
villa_default
villa_nvsd-net
villa_proxy
Avant toute suppression, j’ai vérifié qu’aucun conteneur ne leur était encore attaché.
Ils ont ensuite été supprimés individuellement.
Les réseaux restant correspondent maintenant aux services réellement actifs :
proxy
npm_default
nvsd_homelab_internal
fractal-studio
concerto-infini_default
bridge
host
none
Étape 14 — Supprimer les anciennes images
La dernière partie du nettoyage concernait les anciennes images Docker :
nvsd-homelab:latest
concerto-infini-phase9-web:latest
concerto-infini-phase9-api:latest
portainer/portainer-ce:lts
hello-world:latest
Elles n’étaient plus utilisées par aucun conteneur actif.
Je les ai donc supprimées, puis j’ai lancé :
docker image prune -f
docker builder prune -f
Les images utilitaires comme :
wordpress:cli
curlimages/curl
alpine
ont été conservées, car elles restent pratiques pour la maintenance et les diagnostics.

L’état final du VPS
Après migration et nettoyage, le VPS présentait l’état suivant :
Conteneurs : 13 / 13 actifs
Volumes : 2 / 2 actifs
WordPress : opérationnel
MariaDB : healthy
HTTPS : opérationnel
Port WordPress : aucun port hôte publié
L’organisation des principales stacks est désormais :
/opt/homelab/stacks/
├── concerto-infini/
├── dockge/
├── fractal-studio/
├── npm/
├── nvsd-homelab-wordpress/
├── nvsd-villa/
└── nvsd-web/
Cette structure est beaucoup plus lisible qu’une accumulation de conteneurs, réseaux et volumes créés au fil des expérimentations.
Ce que cette migration m’a appris
Cette migration m’a surtout rappelé qu’un déplacement WordPress ne se résume pas à copier un dossier.
Il faut penser en même temps à :
- la base de données ;
- les fichiers ;
- les médias ;
- les URL enregistrées par WordPress ;
- les données sérialisées ;
- les volumes Docker ;
- les réseaux ;
- le reverse proxy ;
- HTTPS ;
- les sauvegardes ;
- le nettoyage des anciennes ressources.
Le plus important a été de procéder par petites étapes et de valider chaque couche avant de continuer :
Sauvegarder
↓
Restaurer
↓
Tester
↓
Changer les URL
↓
Basculer le proxy
↓
Valider HTTPS
↓
Fermer les ports inutiles
↓
Sauvegarder la production
↓
Nettoyer
Cette méthode m’a permis de migrer le site sans perturber les autres services déjà présents sur le VPS.
Conclusion
Le site Homelab a maintenant franchi une étape importante.
Il n’est plus uniquement un projet développé en local : il fait désormais lui-même partie de l’infrastructure qu’il documente.
Le site décrit mon Homelab, mais il est également hébergé par ce Homelab.
C’est finalement assez représentatif de la philosophie du projet : apprendre en construisant, documenter ce qui fonctionne, conserver les erreurs utiles et améliorer progressivement l’infrastructure.
La suite pourra maintenant se concentrer davantage sur les contenus et les réalisations hébergées : Concerto à l’Infini, Fractal Studio et les prochains services du Homelab.
