---
title: "Hugo sur KVM : installer une VM Ubuntu pour site statique"
description: "Comment installer une VM Ubuntu 24.04 sur KVM avec libvirt, déployer Hugo Extended et le thème LoveIt, et configurer nginx comme proxy inverse sur un NUC8i3BEH."
url: "https://www.arleo.eu/posts/hugo-vm-installation/"
language: "fr"
datePublished: "2026-05-03T09:00:00+02:00"
dateModified: "2026-05-15T23:51:25+02:00"
tags: ["infrastructure","nginx","homelab","mcp"]
categories: ["infrastructure"]
contentSignal: "ai-train=no, search=yes, ai-input=yes"
---

# Hugo sur KVM : installer une VM Ubuntu pour site statique
Comment installer une VM Ubuntu 24.04 sur KVM avec libvirt, déployer Hugo Extended et le thème LoveIt, et configurer nginx comme proxy inverse sur un NUC8i3BEH.



## ⚡ En bref

Migration progressive de **Grav CMS** vers **Hugo** — un générateur de site statique. L'objectif est d'isoler Hugo dans une VM KVM dédiée sur le NUC8i3BEH, avec nginx sur le host en proxy inverse. Le site statique généré est servi par nginx dans la VM, sans PHP, sans base de données, sans surface d'attaque applicative.

- 🖥️ **Host** : NUC8i3BEH Ubuntu 24.04 — nginx proxy + KVM
- 🗄️ **Disque VM** : NVMe externe Samsung X5 (exFAT → image ext4 loop)
- 🌐 **Accès** : [hugo-test.arleo.eu](https://hugo-test.arleo.eu)
- 🎨 **Thème** : [LoveIt](https://github.com/dillonzq/LoveIt)

## 🧠 Pourquoi

Grav CMS est excellent mais repose sur PHP — une surface d'attaque non négligeable. Hugo génère du HTML statique pur : zéro PHP, zéro base de données, zéro vulnérabilité applicative. Les performances sont aussi radicalement meilleures — le HTML est servi directement par nginx sans traitement dynamique.

L'isolation dans une VM KVM offre un avantage supplémentaire : si la VM est compromise, le host reste intact. Le proxy nginx du host ne fait que transmettre les requêtes vers la VM sans exposer d'autres services.

### Architecture finale

```
Internet → Cloudflare → nginx (NUC host) → VM KVM (192.168.122.69)
                                                    ↓
                                             Hugo + nginx
                                           (HTML statique)
```

## 🔧 Ce qui a été fait

### 1. Installation KVM sur le host Ubuntu 24.04

```bash
sudo apt install -y \
  qemu-kvm libvirt-daemon-system libvirt-clients \
  virtinst bridge-utils cloud-image-utils \
  cockpit-machines iptables

sudo usermod -aG libvirt jm
sudo usermod -aG kvm jm
sudo systemctl enable --now libvirtd

# Activer le réseau NAT par défaut
sudo virsh net-start default
sudo virsh net-autostart default
```

### 2. Problème exFAT — image ext4 loop sur le NVMe

Le disque NVMe externe Samsung X5 est formaté en **exFAT** — ce système de fichiers ne supporte pas les permissions Unix (`chown`). QEMU ne peut donc pas lire les images disque stockées dessus directement.

Solution : créer une image ext4 dans un fichier sur le volume exFAT :

```bash
# Créer une image ext4 de 25 Go sur le NVMe exFAT
sudo dd if=/dev/zero of=/mnt/X5/libvirt-pool.img bs=1G count=25 status=progress
sudo mkfs.ext4 /mnt/X5/libvirt-pool.img

# Monter l'image
sudo mkdir -p /mnt/libvirt-kvm
sudo mount -o loop /mnt/X5/libvirt-pool.img /mnt/libvirt-kvm

# Persistance au reboot
echo "/mnt/X5/libvirt-pool.img /mnt/libvirt-kvm ext4 loop,nofail 0 0" \
  | sudo tee -a /etc/fstab

# Permissions pour QEMU
sudo chown libvirt-qemu:kvm /mnt/libvirt-kvm
sudo chmod 755 /mnt/libvirt-kvm

# Pool libvirt dédié
sudo virsh pool-define-as kvm-pool dir --target /mnt/libvirt-kvm
sudo virsh pool-autostart kvm-pool
sudo virsh pool-start kvm-pool
```

### 3. Création de la VM avec cloud-init

```bash
# Télécharger l'image Ubuntu 24.04 cloud
wget -O /mnt/libvirt-kvm/ubuntu-24.04-server.img \
  https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img

# Créer le disque VM (20 Go, backing file)
qemu-img create \
  -F qcow2 -b /mnt/libvirt-kvm/ubuntu-24.04-server.img \
  -f qcow2 /mnt/libvirt-kvm/hugo-vm.qcow2 20G

sudo chown libvirt-qemu:kvm /mnt/libvirt-kvm/hugo-vm.qcow2

# Cloud-init avec clé SSH
SSH_KEY=$(cat /home/jm/.ssh/authorized_keys | head -1)
cat > /tmp/user-data << EOF
#cloud-config
hostname: hugo-vm
users:
  - name: jm
    sudo: ALL=(ALL) NOPASSWD:ALL
    shell: /bin/bash
    lock_passwd: false
    ssh_authorized_keys:
      - $SSH_KEY
packages:
  - nginx
  - git
  - curl
runcmd:
  - systemctl enable nginx
  - systemctl start nginx
EOF

cloud-localds /mnt/libvirt-kvm/hugo-vm-cloud-init.img \
  /tmp/user-data /tmp/meta-data
```

### 4. Démarrage de la VM

```bash
sudo virt-install \
  --name hugo-vm \
  --ram 1024 \
  --vcpus 1 \
  --disk path=/mnt/libvirt-kvm/hugo-vm.qcow2,format=qcow2,bus=virtio \
  --disk path=/mnt/libvirt-kvm/hugo-vm-cloud-init.img,device=cdrom \
  --os-variant ubuntu24.04 \
  --network network=default,model=virtio \
  --graphics none \
  --import \
  --noautoconsole \
  --autostart

# Récupérer l'IP
sudo virsh net-dhcp-leases default
# → 192.168.122.69
```

### 5. Installation de Hugo Extended dans la VM

```bash
ssh jm@192.168.122.69

HUGO_VERSION="0.147.0"
wget -q -O /tmp/hugo.deb \
  "https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-amd64.deb"
sudo dpkg -i /tmp/hugo.deb
hugo version
# hugo v0.147.0+extended linux/amd64
```

### 6. Initialisation du site Hugo avec LoveIt

```bash
mkdir -p ~/hugo-site && cd ~/hugo-site
hugo new site . --force
git init
git submodule add https://github.com/dillonzq/LoveIt.git themes/LoveIt
```

### 7. Configuration nginx dans la VM

```nginx
server {
    listen 80 default_server;
    server_name _;
    root /var/www/hugo;
    index index.html;

    location = / {
        return 302 /fr/;
    }

    location / {
        try_files $uri $uri/ =404;
    }
}
```

### 8. Script de déploiement

```bash
cat > ~/deploy.sh << 'EOF'
#!/bin/bash
cd ~/hugo-site
hugo --minify
sudo rsync -a --delete public/ /var/www/hugo/
sudo chown -R www-data:www-data /var/www/hugo/
echo "Déployé — $(date)"
EOF
chmod +x ~/deploy.sh
```

### 9. Proxy nginx sur le host

```nginx
server {
    listen 443 ssl http2;
    server_name hugo-test.arleo.eu;

    include snippets/ssl.conf;

    location / {
        proxy_pass         http://192.168.122.69:80;
        proxy_http_version 1.1;
        proxy_set_header   Host              $host;
        proxy_set_header   X-Real-IP         $remote_addr;
        proxy_set_header   X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Proto $scheme;
    }
}
```

### Points de friction rencontrés

| Problème | Cause | Solution |
|---|---|---|
| Réseau libvirt inactif | iptables absent | `apt install iptables` |
| Permission denied sur qcow2 | disque exFAT → pas de chown | Image ext4 loop dans le fichier exFAT |
| Cloud-init ne crée pas le user | Clé SSH absente du host | `virt-customize` pour injecter directement |
| SSH refusé (publickey) | Clé privée absente sur le host | Générer `hugo_vm` + injecter via virt-customize |
| nginx 404 | Permissions home jm (750) | Déplacer public/ vers /var/www/hugo |

## 🏁 Conclusion

La VM Hugo est opérationnelle sur [hugo-test.arleo.eu](https://hugo-test.arleo.eu). Le site statique est servi par nginx dans la VM, proxifié par le host. La prochaine étape est la migration du contenu Grav vers Hugo et le développement d'un MCP Hugo pour permettre la gestion des pages directement depuis Claude.ai.

**Pour aller plus loin :**

- 💡 Développer un MCP Hugo (FastAPI + OAuth) sur le modèle de [grav-mcp-server](https://arleo.eu/fr/grav-mcp-server)
- 💡 Automatiser le rebuild Hugo via webhook Git
- 💡 Configurer la sauvegarde de la VM vers le NAS QNAP



## Tags

- infrastructure
- nginx
- homelab
- mcp

## Categories

- infrastructure
