Guide de déploiement

Windmill sur VPS : orchestration TypeScript/Python sans lock-in

Déployer sur un VPS Cloud →

Tutoriel

Windmill sur VPS : orchestration TypeScript/Python sans lock-in

Automatisation11 min de lecture7 étapes

n8n 3.0, sorti en octobre 2026, impose Docker comme seule voie de déploiement et supprime plus de 30 nœuds historiques. Pour les équipes qui évaluent leurs options, Windmill s'impose comme l'alternative la plus directe : vous écrivez du TypeScript ou du Python natif, vous exécutez depuis l'éditeur web, et vous orchestrez des dizaines de workers sur un seul VPS. Pas de plan payant pour les variables secrètes, pas de nœuds proprietaires — juste du code versionné dans un workspace Git. Ce guide vous amène à une instance Windmill v1.830 en production en moins d'une heure.

Sommaire· Pourquoi Windmill plutôt que n8n ou Make en 20261/15
  1. 01Pourquoi Windmill plutôt que n8n ou Make en 2026
  2. 02Bénéfices concrets pour les équipes DevOps et agences
  3. 03Prérequis chiffrés
  4. 04Configuration minimale et recommandée
  5. 05Déploiement Docker Compose en 7 étapes
  6. 06Configuration : workspace, variables secrètes et crons
  7. 07Les réglages essentiels post-installation
  8. 08Exemple de workflow Python complet
  9. 09Script Python : import API → filtre → PostgreSQL
  10. 10Durcissement et sécurité
  11. 11Dépannage — erreurs fréquentes
  12. 125 erreurs réelles et leurs correctifs
  13. 13Vers la production : checklist finale
  14. 14Points de validation avant mise en production
  15. 15Windmill vs n8n vs Temporal

Pourquoi Windmill plutôt que n8n ou Make en 2026

n8n 3.0 marque un tournant : Docker obligatoire, 30+ nœuds supprimés, et les nœuds Code qui ne peuvent plus lire les variables d'environnement. Make reste un SaaS fermé avec des limites d'opérations par mois. Windmill prend une direction opposée : tout votre code est un script de première classe, versionné, testable unitairement, et exécutable depuis un terminal comme depuis l'UI. La licence AGPLv3 garantit que la version self-hosted reste fonctionnellement identique à l'offre cloud — pas de features réservées à l'entreprise pour l'usage courant.

Bénéfices concrets pour les équipes DevOps et agences

  • TypeScript et Python natifs — vos scripts s'exécutent dans un worker Node.js ou Python sans transpilation ni couche de nœuds intermédiaires ; les dépendances npm/pip sont résolues automatiquement par Windmill à la première exécution.
  • Éditeur web avec exécution directe — écrivez, testez et relancez un script depuis le navigateur en quelques secondes, sans avoir à pousser un commit ou redémarrer un service.
  • Multilocataire intégré — un seul déploiement supporte plusieurs workspaces isolés, idéal pour une agence gérant plusieurs clients ou une équipe avec des environnements dev/staging/prod.
  • Jobs cron et webhooks sans plugin — planifier un job 0 9 * * 1-5 ou exposer un endpoint webhook /api/w/<workspace>/jobs/run/p/<path> est une opération native, pas un add-on.
  • Variables secrètes chiffrées — les secrets sont chiffrés en base et jamais exposés dans les logs ; chaque workspace a son propre périmètre de secrets.
  • Pas de lock-in — tous les scripts, flows et ressources sont exportables en JSON/YAML et importables dans n'importe quel autre déploiement Windmill.

Prérequis chiffrés

Windmill s'appuie sur PostgreSQL pour la persistance et sur un ou plusieurs workers pour l'exécution. Le serveur HTTP lui-même est léger ; c'est la charge des workers qui dimensionne le VPS. Comptez 1 worker par vCPU disponible et environ 1 à 2 Go de RAM par worker Python actif (les dépendances pip sont installées en sandbox et mises en cache sur disque).

Configuration minimale et recommandée

  • Minimum absolu — 2 vCPU, 4 Go de RAM, 20 Go de disque SSD ; convient à un workspace solo avec 1 worker et des jobs occasionnels.
  • Petite équipe (recommandé) — 4 vCPU, 8 Go de RAM, 40 Go SSD ; permet 3 workers simultanés et PostgreSQL sur le même hôte sans saturation mémoire.
  • Équipe ou multi-clients — 8 vCPU, 16 Go de RAM, 80 Go SSD ; supporte 6 à 8 workers, plusieurs workspaces actifs et des jobs Python avec dépendances lourdes.
  • OS — Ubuntu 22.04 LTS ou Debian 12 ; Docker Engine 24+ et Docker Compose v2 requis.
  • Réseau — une IPv4 dédiée et un nom de domaine pour le certificat TLS ; Windmill expose par défaut le port 8000 derrière un reverse proxy.

Déploiement Docker Compose en 7 étapes

  1. Installer Docker et Docker Compose v2

    Sur Ubuntu 22.04 ou Debian 12 : curl -fsSL https://get.docker.com | sh && docker compose version. Vérifiez que la commande retourne Docker Compose version v2.x.x (sans tiret). Si votre système propose encore docker-compose (v1), désinstallez-le : apt remove docker-compose.

  2. Récupérer le docker-compose.yml officiel

    Créez un répertoire dédié et récupérez la configuration de référence : mkdir -p /opt/windmill && cd /opt/windmill && curl -fsSL https://raw.githubusercontent.com/windmill-labs/windmill/main/docker-compose.yml -o docker-compose.yml. Ce fichier déclare quatre services : db (PostgreSQL 16), windmill_server, windmill_worker et lsp (serveur de complétion de code).

  3. Créer le fichier .env

    Windmill attend deux variables obligatoires. Générez une clé aléatoire : openssl rand -hex 32. Puis créez /opt/windmill/.env avec : WM_BASE_URL=https://windmill.votre-domaine.com et WINDMILL_SECRET_KEY=<clé générée>. Ne commitez jamais ce fichier — ajoutez .env à votre .gitignore si vous versionnez la configuration.

  4. Ajuster le nombre de workers

    Par défaut, docker-compose.yml démarre 1 replica du service windmill_worker. Pour en démarrer 3 : docker compose up -d --scale windmill_worker=3. Sur un VPS 4 vCPU / 8 Go, 2 ou 3 workers est le bon équilibre. Vous pouvez ajuster à chaud sans redémarrer le serveur : docker compose up -d --no-recreate --scale windmill_worker=2.

  5. Configurer Nginx en reverse proxy avec TLS

    Installez Nginx et Certbot : apt install -y nginx certbot python3-certbot-nginx. Créez /etc/nginx/sites-available/windmill avec un bloc server écoutant le port 80, un proxy_pass http://127.0.0.1:8000; et les en-têtes X-Real-IP, X-Forwarded-For, Upgrade et Connection (pour les WebSockets). Obtenez le certificat : certbot --nginx -d windmill.votre-domaine.com. Certbot modifie automatiquement le vhost pour écouter en HTTPS.

  6. Démarrer la stack et créer le workspace initial

    Lancez la stack : cd /opt/windmill && docker compose up -d. Attendez 30 secondes que PostgreSQL soit prêt, puis ouvrez https://windmill.votre-domaine.com dans un navigateur. L'interface vous propose de créer un workspace — choisissez un identifiant court (prod, acme-client) — et de définir le compte administrateur. Ce compte est local à Windmill ; vous pourrez connecter un fournisseur SSO (GitHub, OIDC) depuis Settings → Authentication.

  7. Activer le redémarrage automatique et vérifier les logs

    Ajoutez la politique de redémarrage à la stack : dans docker-compose.yml, assurez-vous que chaque service a restart: unless-stopped. Rechargez si nécessaire : docker compose up -d. Vérifiez les logs du serveur : docker compose logs -f windmill_server. La ligne Windmill server started on port 8000 confirme que l'instance est opérationnelle. Pour les workers : docker compose logs -f windmill_worker.

Configuration : workspace, variables secrètes et crons

Une fois l'instance démarrée, trois zones de configuration sont à maîtriser avant de créer vos premiers workflows.

Les réglages essentiels post-installation

  • Workspace et permissions — dans Settings → Workspace, définissez le fuseau horaire (utilisé pour les crons) et activez le mode Auto-approve executions uniquement si tous les membres sont de confiance. Par défaut, les scripts créés par des utilisateurs non-admin passent en mode de revue avant exécution en production.
  • Variables et ressources — Variables stocke des clés scalaires (tokens, URLs) chiffrées AES-256. Resources stocke des objets structurés (connexions de bases de données, credentials OAuth) avec un schéma JSON typé. Préférez les ressources pour tout ce qui contient plusieurs champs : moins d'erreurs de copier-coller.
  • Schedules (crons) — dans l'éditeur d'un script, cliquez Add schedule. La syntaxe acceptée est le format cron standard à 5 champs. Le timezone par workspace s'applique automatiquement : 0 8 * * 1-5 déclenche bien à 8h00 heure du workspace, pas UTC.
  • Webhooks — chaque script expose un endpoint de la forme /api/w/<workspace>/jobs/run/p/<chemin-du-script>. Authentifiez les appels entrants avec un token généré dans Settings → Tokens. Passez les paramètres du script en corps JSON POST.
  • Synchronisation Git — dans Settings → Git Sync, connectez un dépôt Git pour pousser automatiquement tous les scripts, flows et ressources à chaque modification. Idéal pour la traçabilité et le déploiement entre environnements.

Exemple de workflow Python complet

Voici un script Python concret : il interroge une API externe, filtre les résultats et insère les lignes dans une base PostgreSQL via une ressource Windmill. Créez un nouveau script de type Python 3.11, collez le code ci-dessous et exécutez-le directement depuis l'éditeur pour valider.

Script Python : import API → filtre → PostgreSQL

  • Déclaration des dépendances — les lignes # requirements: en tête du script indiquent à Windmill les packages pip à installer dans le sandbox isolé : # requirements:\n# httpx\n# psycopg2-binary. Windmill gère le cache de ces dépendances entre exécutions.
  • Signature de la fonction principale — Windmill appelle toujours la fonction def main(...). Les paramètres sont injectés depuis l'UI, le cron ou le corps du webhook : def main(api_url: str, db: dict) -> dict:. Le type dict pour db correspond à une ressource PostgreSQL.
  • Appel HTTP avec httpx — import httpx; resp = httpx.get(api_url, timeout=10); resp.raise_for_status(); data = resp.json(). Windmill capture les exceptions non gérées et les affiche dans le journal d'exécution avec la stack trace complète.
  • Filtrage et insertion — rows = [r for r in data if r.get('active')]; conn = psycopg2.connect(**db); cur = conn.cursor(); cur.executemany('INSERT INTO items(id, name) VALUES (%(id)s, %(name)s) ON CONFLICT DO NOTHING', rows); conn.commit(). La ressource db est passée comme dictionnaire Python — les clés correspondent aux paramètres de psycopg2.connect.
  • Valeur de retour — return {'inserted': len(rows), 'source': api_url}. La valeur retournée est affichée dans l'UI et accessible aux étapes suivantes d'un Flow.

Durcissement et sécurité

Limitez l'accès réseau au VPS : fermez le port 8000 dans UFW (ufw deny 8000/tcp) — seul Nginx doit y accéder depuis localhost. Activez les headers de sécurité dans Nginx : add_header X-Frame-Options SAMEORIGIN; add_header X-Content-Type-Options nosniff; add_header Referrer-Policy strict-origin-when-cross-origin. Configurez les sauvegardes PostgreSQL : docker exec windmill-db-1 pg_dump -U windmill windmill | gzip > /backups/windmill-$(date +%Y%m%d).sql.gz. Planifiez ce dump avec un cron systemd ou… un job Windmill lui-même. Activez la politique de mots de passe dans Settings → Security et forcez 2FA pour les comptes admin. Limitez les permissions des workers non-root : Windmill supporte les Worker Groups avec des images Docker restreintes pour les scripts non fiables.

Dépannage — erreurs fréquentes

Voici les cinq problèmes rencontrés le plus souvent lors d'un premier déploiement Windmill, avec leurs causes réelles et leurs corrections.

5 erreurs réelles et leurs correctifs

  • connection refused au démarrage du serveur — le conteneur windmill_server démarre avant que PostgreSQL soit prêt. Ajoutez un healthcheck sur le service db et une clause depends_on: db: condition: service_healthy sur windmill_server. Sans cela, le serveur tente de se connecter à PostgreSQL pendant son initialisation et abandonne. Vérifiez : docker compose logs db | grep 'ready to accept'.
  • Workers qui restent IDLE indéfiniment — cause classique : la variable DATABASE_URL dans l'environnement des workers pointe vers localhost au lieu du nom du service Docker (db). Dans docker-compose.yml, la valeur correcte est postgresql://windmill:windmill@db/windmill. localhost depuis un conteneur ne résout pas le service PostgreSQL de la stack.
  • Scripts Python qui échouent avec ModuleNotFoundError — Windmill résout les dépendances pip au premier lancement du script dans un cache local. Si le worker n'a pas d'accès internet (pare-feu restrictif), l'installation silencieuse échoue. Vérifiez : docker exec <worker-id> pip install httpx. Ouvrez le port 443 sortant pour pypi.org et files.pythonhosted.org, ou montez un miroir pip interne via la variable PIP_INDEX_URL.
  • Webhook retourne 403 Forbidden — le token passé en header Authorization: Bearer <token> est correct, mais le script est en mode Require approval. Désactivez ce mode dans l'éditeur du script (Settings → Execution policy → Direct execution) ou utilisez un token de service avec le rôle executor.
  • Cron qui ne se déclenche pas à l'heure prévue — le fuseau horaire du workspace est UTC par défaut. Si votre workspace est en Africa/Casablanca (UTC+1 en hiver, UTC+0 en été selon DST), une expression 0 9 * * * déclenche à 9h00 du fuseau du workspace. Vérifiez le timezone dans Settings → Workspace → Timezone et relancez le scheduler : docker compose restart windmill_server.

Vers la production : checklist finale

Avant d'exposer Windmill à du trafic réel ou à des jobs critiques, parcourez cette liste. Elle couvre les points qui passent le plus souvent à la trappe lors d'un premier déploiement.

Points de validation avant mise en production

  • TLS valide et HSTS — vérifiez que https://windmill.votre-domaine.com répond sans avertissement de certificat et ajoutez Strict-Transport-Security: max-age=31536000 dans le vhost Nginx.
  • Sauvegardes testées — faites un dump PostgreSQL, restaurez-le dans un conteneur de test et vérifiez que l'interface Windmill se connecte. Une sauvegarde non testée n'existe pas.
  • Monitoring des workers — la page Admin → Workers affiche l'état en temps réel. Branchez une alerte (Grafana, UptimeRobot, ou un job Windmill lui-même) si le nombre de workers actifs passe sous 1.
  • Rotation des secrets — les variables Windmill sont chiffrées avec la WINDMILL_SECRET_KEY. Si vous perdez cette clé, les secrets chiffrés en base sont irrécupérables. Sauvegardez la clé dans un gestionnaire de secrets (Vaultwarden, Bitwarden) séparé du VPS.
  • Version fixée dans docker-compose.yml — remplacez image: ghcr.io/windmill-labs/windmill:latest par image: ghcr.io/windmill-labs/windmill:1.830.0 pour éviter les mises à jour automatiques non contrôlées. Mettez à jour délibérément en consultant le CHANGELOG.
  • Git Sync activé — connectez un dépôt privé pour versionner tous vos scripts et flows. En cas de perte du VPS, vous restaurez la base et réimportez depuis Git.

Windmill vs n8n vs Temporal

Faites défiler le tableau

CritèreWindmill 1.830n8n 3.xTemporal Cloud/Self-hosted
Langage des workflowsTypeScript, Python, Go, BashJavaScript (nœuds) + Code nodes limitésGo, Java, Python, TypeScript via SDK
Modèle de déploiementDocker Compose, 1 image uniqueDocker obligatoire depuis v3.0Docker ou Temporal Cloud SaaS
LicenceAGPLv3 (self-host complet)Sustainable Use License (restrictions agences)MIT (core) + offre cloud payante
Variables secrètes self-hostedInclus, chiffrées AES-256InclusInclus (Temporal Namespace)
Éditeur web intégréOui — IDE complet avec autocomplétionOui — canvas nodalNon — développement en local uniquement
MultilocataireOui — workspaces isolés natifsPartiel — instances séparées recommandéesOui — Namespaces Temporal
RAM minimale4 Go (1 worker + PostgreSQL)2 Go (SQLite), 4 Go (PostgreSQL)4 Go (self-hosted) / N/A (cloud)
Durée max d'un workflowSans durée limite (jobs longue durée)Limitée par le timeout des nœudsSans limite (durabilité des activités)
Courbe d'apprentissageFaible — code Python/TS standardFaible — canvas visuelÉlevée — modèle d'activités/signaux

Un VPS prêt pour Windmill en quelques minutes

ServOrbit propose des VPS avec accès root, IPv4 dédiée et choix d'OS Ubuntu/Debian. Montez votre stack Windmill avec Docker Compose dès le premier accès SSH.

Besoin d'aide ?

Parcourez notre centre d'aide et notre FAQ, ou contactez notre équipe — rappel, WhatsApp ou e-mail. Support en français, anglais et arabe.

Écrire sur WhatsApps'ouvre dans un nouvel onglet