tva
← コラム

2026年のWindmillセルフホスティング:ワーカー、PostgreSQL、分離、安全な更新

ベンダーの公式文書をもとに、運用管理、移行の判断、検証可能なリリース基準を具体化する、本番運用向けの最新の補足記事です。

2026年に変わったこと

運用上の境界条件が変化したため、このテーマを改めて検討します。長期的に有効な原則は残る一方、現行バージョンでは過去の近道が不十分、あるいは危険になっている場合があります。本稿は2026年7月14日時点で入手できる公式文書を起点に、事実と自社環境での判断を分け、設定変更をすべて管理下で行う本番環境の変更として扱います。

最新の一次資料

この更新版の使い方

まず一次資料を確認し、実際に稼働しているバージョンを記録し、設定を変える前に観測可能な成果を定義します。実際の運用を代表する環境で、最小かつ元に戻せる変更を試します。コマンドが成功しただけでは受け入れ基準を満たしません。サービスの健全性、データの完全性、レイテンシー、セキュリティ境界、ロールバック時間まで確認します。旧稿の診断手順で現在も有効な部分は運用基盤として残しますが、バージョン依存の例は必ず現行文書と照合します。

リリース前に、設定差分、少なくとも1回は復元を確認したバックアップまたはスナップショット、変更を元に戻すためのコマンドを記録します。最初の本番運用期間を監視する担当者と、想定した指標が悪化した場合にエスカレーションを承認する担当者を別々に決めます。アラートは、発報した構成要素だけでなく、利用者にどのようなリスクがあるかを示す必要があります。確認期間には、エラー率、キューの深さ、リソースの飽和、処理のレイテンシー、データの完全性を、合意したベースラインと比較します。平均値だけでなく分布の裾も確認します。平均が安定していても、少数ながら重要な処理の失敗が隠れている場合があるためです。遅延したジョブ、再試行、定期実行タスク、下流へのエクスポートが完了してから変更を完了扱いにします。復旧中の手作業はすべて記録します。文書化されていない復旧操作が必要なら、運用手順書はまだ不完全だという証拠です。このリリース管理によって、次のアップグレードで再利用できる証跡が残り、同じ依存関係をチームが調べ直さずに済みます。

運用の基盤

ワークフロー自動化プラットフォームは現代の開発チームに不可欠ですが、Windmill Cloudなどのクラウドサービスは、利用が増えるにつれて費用がかさむことがあります。Docker ComposeとTraefikを使い、構築を妨げるPostgreSQLの認証問題を解決しながら、Ubuntu上で自社のWindmillインスタンスを構築する方法を紹介します。

構築するもの

このチュートリアルを終えると、以下を構築できます:

  • HTTPSに対応した、正常に動作するWindmill環境
  • Traefik経由のLet’s Encryptによる自動SSL証明書
  • 適切な認証を備えた本番運用向けPostgreSQLデータベース
  • リソース使用量を最適化したワーカー設定
  • 既存のDockerインフラとの統合
  • 業務のワークフロー自動化に使える本番運用向けの構成

月額コスト:税別(プライマリIPv4アドレス1個込み)5.99ユーロから(Hetzner CX23、4GB RAM、2026年10月時点)+ ドメイン費用。同じインフラで複数の自動化ツールを運用できます

前提条件

  • DockerとDocker ComposeがインストールされたUbuntu 24.04 LTSサーバー
  • 既存のTraefikリバースプロキシセットアップ(Traefik設定についてはn8nセットアップガイドを参照してください)
  • サーバーのIPアドレスを指すドメイン名
  • 最低4GB RAMと2 vCPUを推奨
  • SSHアクセスと基本的なコマンドラインの知識

Windmillの概要

Windmillは以下を提供するオープンソースのワークフローエンジンです:

  • TypeScript/Python/Goサポート付きのビジュアルワークフローエディター
  • ジョブスケジューリングと実行管理
  • API連携機能
  • チームでの共同作業機能
  • セルフホスティング対応。無料のCommunity Editionでは実行回数が無制限

n8nのノードベースのアプローチとは異なり、Windmillは強力な開発環境を備えたコードを中心に記述するワークフローを重視しています。

ステップ1:サーバーの準備とディレクトリ構造

まず、サーバー環境を準備します。競合を避けるために、Windmillインスタンスには食べ物の名前を使った命名規則を使用します:

# Create Windmill directory (first instance: "pizza")
mkdir -p /opt/windmill-pizza
cd /opt/windmill-pizza

# Create required subdirectories
mkdir -p postgres-data windmill-data lsp-cache

# Verify directory structure
ls -la

命名規則:複数のWindmillインスタンスにはシンプルな食べ物の名前を使用します:

  • 最初のインスタンス:pizza
  • 追加インスタンス:pasta、salad、soup、burgerなど
  • 競合を回避し、管理を容易にします

ステップ2:環境設定

適切な認証情報を含む安全な環境ファイルを作成します:

# Generate a secure hex password (no special characters!)
SECURE_PASSWORD=$(openssl rand -hex 16)

# Create environment file
cat > /opt/windmill-pizza/.env << EOF
# Windmill Image Version (pin a release; change it deliberately when you update)
WM_IMAGE=ghcr.io/windmill-labs/windmill:1.767.0

# Database Configuration - SECURE PASSWORDS
DATABASE_URL=postgresql://postgres:${SECURE_PASSWORD}@windmill-db:5432/windmill_pizza?sslmode=disable
POSTGRES_PASSWORD=${SECURE_PASSWORD}
POSTGRES_DB=windmill_pizza
POSTGRES_USER=postgres

# Windmill Configuration
BASE_URL=https://windmill.yourdomain.com
RUST_LOG=info

# Worker Configuration
WORKER_GROUP=default
KEEP_JOB_DIR=false

# Instance Identifier
INSTANCE_NAME=pizza
EOF

# The file holds the database password: make it readable by its owner only
chmod 600 /opt/windmill-pizza/.env

重要:windmill.yourdomain.comを実際のドメインに置き換えてください。

ステップ3:Docker Compose設定

メインのDocker Compose設定を作成します:

cat > /opt/windmill-pizza/docker-compose.yml << 'EOF'
services:
  # PostgreSQL Database for Windmill
  windmill-db:
    image: postgres:16
    container_name: windmill-pizza-db
    restart: unless-stopped
    environment:
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_DB: ${POSTGRES_DB}
      POSTGRES_USER: ${POSTGRES_USER}
    volumes:
      - ./postgres-data:/var/lib/postgresql/data
    networks:
      - proxy
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 10s
      timeout: 5s
      retries: 5

  # Windmill Server
  windmill-server:
    image: ${WM_IMAGE}
    container_name: windmill-pizza-server
    restart: unless-stopped
    environment:
      - DATABASE_URL=${DATABASE_URL}
      - BASE_URL=${BASE_URL}
      - RUST_LOG=${RUST_LOG}
      - MODE=server
    networks:
      - proxy
    depends_on:
      windmill-db:
        condition: service_healthy
    volumes:
      - ./windmill-data:/tmp/windmill
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.windmill-pizza.rule=Host(`windmill.yourdomain.com`)"
      - "traefik.http.routers.windmill-pizza.entrypoints=https"
      - "traefik.http.routers.windmill-pizza.tls.certresolver=letsencrypt"
      - "traefik.http.services.windmill-pizza.loadbalancer.server.port=8000"

  # Windmill Worker
  windmill-worker:
    image: ${WM_IMAGE}
    container_name: windmill-pizza-worker
    restart: unless-stopped
    environment:
      - DATABASE_URL=${DATABASE_URL}
      - BASE_URL=${BASE_URL}
      - RUST_LOG=${RUST_LOG}
      - MODE=worker
      - WORKER_GROUP=${WORKER_GROUP}
      - KEEP_JOB_DIR=${KEEP_JOB_DIR}
    networks:
      - proxy
    depends_on:
      windmill-db:
        condition: service_healthy
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./windmill-data:/tmp/windmill
      - worker_dependency_cache:/tmp/windmill/cache
    deploy:
      resources:
        limits:
          cpus: '1'
          memory: 2G

networks:
  proxy:
    external: true

volumes:
  worker_dependency_cache:
    driver: local
EOF

重要:Traefikラベルのドメインを実際の構成に合わせて更新してください。

ステップ4:PostgreSQLパスワード問題(重大な問題)

多くのWindmillの構築で失敗が起きるのが、この部分です。根本原因を特定するまでに、かなりの調査が必要でした:

問題:パスワード内の特殊文字

openssl rand -base64 32を使用してパスワードを生成すると、出力に+、/、=が含まれることがあります。DATABASE_URL内では、これらの文字をパーセントエンコードする必要があります。エンコードしないとURLの解析に支障が生じ、PostgreSQLの認証エラーとして現れることがあります。16進数のパスワードを使えば、このエンコード処理は不要です。

問題のあるパスワードの例:

# Unless percent-encoded, the "/" in this password breaks DATABASE_URL:
PASSWORD="305t6m9KrChkvbyN/FLEYQ6pqAGlApn9rbJPH3D5y9g="

解決策:16進数のみのパスワード

特殊文字を含まない16進数のみのパスワードを使用します:

# This WORKS reliably:
PASSWORD=$(openssl rand -hex 16)
# Example result: 5781b14ec0ec1bc184653ffa5e379411

追加のPostgreSQL設定の問題

  • ユーザー設定:Windmillの設定例と同様に、スーパーユーザーのpostgresを使用します。カスタムユーザーは、Windmillのマイグレーションで必要なwindmill_adminとwindmill_userのロールを付与してからでなければ機能しません(Windmillのセルフホスティングドキュメントを参照)
  • 永続ボリューム:既存のデータボリュームに異なる認証情報が含まれている場合、PostgreSQLはPOSTGRES_PASSWORD環境変数を無視
  • URL形式:Windmillの設定例のように、データベースが内部のDockerネットワークからのみ到達可能な場合は、データベースURLに?sslmode=disableを含めます。ほかのネットワーク経由で接続するデータベースには、requireなどのSSLモードを使用してください

ステップ5:インストールと起動

修正した設定でWindmillをインストールします:

cd /opt/windmill-pizza

# Verify configuration syntax
docker compose config --quiet

# Pull images
docker compose pull

# Start services
docker compose up -d

# Check status
docker compose ps

以下のような出力が表示されるはずです:

NAME                    STATUS                    PORTS
windmill-pizza-db       Up (healthy)              5432/tcp
windmill-pizza-server   Up                        8000/tcp
windmill-pizza-worker   Up                        8000/tcp

ステップ6:よくある問題のトラブルシューティング

問題1:PostgreSQL認証の失敗

症状:

windmill-pizza-server | Error: password authentication failed for user "postgres"

解決策:データベースをリセットすると、Windmillのデータがすべて削除されます。新規インストール時、または検証済みのバックアップがある場合にのみ実行してください。

# WARNING: this deletes all Windmill data (fresh install or verified backup only)
cd /opt/windmill-pizza

# Stop containers
docker compose down --volumes

# Remove old data
rm -rf /opt/windmill-pizza/postgres-data/*

# Regenerate hex password and write it to both variables
NEW_PASSWORD=$(openssl rand -hex 16)
sed -i "s/^POSTGRES_PASSWORD=.*/POSTGRES_PASSWORD=$NEW_PASSWORD/" .env
sed -i "s|^DATABASE_URL=postgresql://postgres:[^@]*@|DATABASE_URL=postgresql://postgres:$NEW_PASSWORD@|" .env

# Restart
docker compose up -d

問題2:コンテナが起動しない

症状:

  • コンテナが即座に終了
  • リソース割り当てエラー

解決策:

# Check container logs
docker logs windmill-pizza-server
docker logs windmill-pizza-db

# Check system resources
docker stats
free -h

問題3:SSL証明書の問題

症状:

  • HTTPSが機能しない
  • 証明書エラー

解決策:

# Check Traefik logs
docker logs traefik

# Verify DNS resolution
nslookup windmill.yourdomain.com

# Restart Traefik if needed
docker restart traefik

ステップ7:アクセスと初期セットアップ

インストールが完了したら:

  • Windmillにアクセス:https://windmill.yourdomain.com
  • デフォルト認証情報:

メール:[email protected]

  • パスワード:changeme
  • セットアップを完了:

管理者パスワードを変更

  • ベースURLを設定
  • ユーザーアカウントをセットアップ

ステップ8:リソース最適化

メモリ割り当て(8GBサーバーの場合)

当社の設定では、リソースを効率的に割り当てます:

  • Windmillサーバー:約800MB
  • Windmillワーカー:2GB(制限付き)
  • PostgreSQL:約500MB
  • システム用に確保する容量:約4.7GB

CPU割り当て(4 vCPUサーバーの場合)

  • ワーカー:1 vCPU(制限付き)
  • その他のサービス:3 vCPU(共有)

スケーリングルール:vCPUあたり1ワーカー、各1〜2GB RAM

ステップ9:本番環境のセキュリティ強化

バックアップスクリプトの作成

cat > /opt/windmill-pizza/backup.sh << 'EOF'
#!/bin/bash
set -euo pipefail
umask 077

# docker compose needs the project directory, also when run from cron
cd /opt/windmill-pizza

DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE=/opt/backups/windmill_pizza_${DATE}.sql
mkdir -p /opt/backups

if ! docker compose exec -T windmill-db pg_dump -U postgres windmill_pizza > "$BACKUP_FILE" || [ ! -s "$BACKUP_FILE" ]; then
  rm -f "$BACKUP_FILE"
  echo "Backup FAILED" >&2
  exit 1
fi
echo "Backup created: $BACKUP_FILE"
EOF

chmod +x /opt/windmill-pizza/backup.sh

監視のセットアップ

cd /opt/windmill-pizza

# Monitor container health
docker compose ps

# Check resource usage
docker stats

# Monitor logs
docker compose logs -f windmill-server

自動アップデートの設定

cat > /opt/windmill-pizza/update.sh << 'EOF'
#!/bin/bash
set -euo pipefail
cd /opt/windmill-pizza

# Back up first; stop here if the backup fails
./backup.sh

# Pull and start the images set in .env (raise WM_IMAGE there to update Windmill)
docker compose pull
docker compose up -d
EOF

chmod +x /opt/windmill-pizza/update.sh

ステップ10:高度な設定

既存SMTPとの連携

当社のn8n構成のようにメールサーバーがある場合は、連携させます:

# Add to docker-compose.yml environment for windmill-server:
- SMTP_HOST=mailserver
- SMTP_PORT=25
- [email protected]
# Only if your mail server requires authentication:
# - SMTP_USERNAME=...
# - SMTP_PASSWORD=...

複数のWindmillインスタンス

分離された環境を必要とするチーム向け:

# Create second instance from the configuration files only (not the data)
mkdir -p /opt/windmill-pasta/{postgres-data,windmill-data,lsp-cache}
cp /opt/windmill-pizza/{.env,docker-compose.yml,backup.sh,update.sh} /opt/windmill-pasta/
chmod 600 /opt/windmill-pasta/.env
cd /opt/windmill-pasta

# Update names, paths and domain
sed -i 's/pizza/pasta/g' .env docker-compose.yml backup.sh update.sh
sed -i 's/windmill.yourdomain.com/pasta.yourdomain.com/g' .env docker-compose.yml

# Generate new password and write it to both variables
NEW_PASSWORD=$(openssl rand -hex 16)
sed -i "s/^POSTGRES_PASSWORD=.*/POSTGRES_PASSWORD=$NEW_PASSWORD/" .env
sed -i "s|^DATABASE_URL=postgresql://postgres:[^@]*@|DATABASE_URL=postgresql://postgres:$NEW_PASSWORD@|" .env

# Start the new instance
docker compose up -d

セキュリティの考慮事項

ネットワーク分離

  • PostgreSQLに到達できるのは、同じDockerネットワーク上のコンテナのみです。そのネットワークをリバースプロキシやほかのサービスと共有している場合は、より厳密に分離するため、別の内部ネットワークを使用してください
  • データベースのポートを外部に公開しない
  • TraefikレベルでのHTTPS終端

リソース制限

  • ワーカーコンテナにCPUとメモリの制限あり
  • リソース制限により、暴走したジョブやリソース枯渇を狙う試みの影響を軽減
  • サーバー容量に基づいて設定可能

SSLセキュリティ

  • Let’s Encrypt証明書の自動取得
  • HTTPからHTTPSへのリダイレクト
  • 最新のTLS設定

監視とメンテナンス

週次ヘルスチェック

cd /opt/windmill-pizza

# Container status
docker compose ps

# Resource usage
docker stats --no-stream

# Log analysis
docker compose logs | grep -i error

月次メンテナンス

# Back up and update containers (update.sh runs backup.sh first)
cd /opt/windmill-pizza
./update.sh

# Clean unused images, containers and networks
docker system prune -f

コスト内訳と比較

月額コスト

セルフホスティングセットアップ:

  • Hetzner CX23(4GB RAM):月額5.99ユーロ(税別、プライマリIPv4アドレス1個込み、2026年10月時点)
  • ドメイン費用:約月額1ユーロ
  • 合計:月額約7ユーロ(税別)

Windmill Cloudとの比較:

  • Cloud:開発者1席あたり月額20ドル、オペレーター1人あたり月額10ドル(2026年10月時点)
  • 節約額:開発者2人以上がそれぞれ席を必要とする場合、年間250ドル以上

パフォーマンスのメリット

セルフホスティングの利点:

  • 無制限のワークフロー実行
  • 外部レート制限なし
  • 完全なデータ制御
  • 独自のシステム連携
  • リソースを柔軟に拡張可能

トラブルシューティングの早見表

簡易診断

cd /opt/windmill-pizza

# Container health
docker compose ps | grep -E "(healthy|Up)"

# Network connectivity
docker network inspect proxy

# Database connection
docker compose exec windmill-db psql -U postgres -d windmill_pizza -c "SELECT version();"

# Log analysis
docker compose logs --tail 50 windmill-server | grep -E "(ERROR|WARN)"

よくあるエラーパターン

  • 「password authentication failed」 → 16進数のパスワードを使用。ボリュームのクリアは、バックアップ後または新規インストール時にのみ実行
  • 「connection refused」 → ネットワーク設定を確認
  • 「certificate errors」 → DNSとTraefikセットアップを検証
  • 「out of memory」 → ワーカーのリソース制限を調整

Windmillインフラのスケーリング

水平スケーリング

大量処理環境向け:

# Add additional workers (under services: in docker-compose.yml)
windmill-worker-2:
  image: ${WM_IMAGE}
  container_name: windmill-pizza-worker-2
  restart: unless-stopped
  environment:
    - DATABASE_URL=${DATABASE_URL}
    - MODE=worker
    - WORKER_GROUP=heavy
  networks:
    - proxy
  depends_on:
    windmill-db:
      condition: service_healthy
  deploy:
    resources:
      limits:
        cpus: '2'
        memory: 4G

垂直スケーリング

サーバーリソースをアップグレード(Hetznerの税別価格、プライマリIPv4アドレス1個込み、2026年10月時点):

  • CX33(8GB RAM):重いワークロード向けに月額8.99ユーロ
  • CX43(16GB RAM):企業での利用向けに月額16.49ユーロ

既存インフラとの統合

n8nとの連携

当社の以前のチュートリアルに沿って、すでにn8nを運用している場合:

  • Windmillはコードを中心に記述するワークフローを処理
  • n8nは画面上で組み立てるシンプルな自動化を処理
  • 両方が同じTraefikプロキシを共有
  • 別々のデータベースで競合を防止

共有サービス

既存のインフラを活用:

  • Traefik:すべてのサービスのSSLを処理
  • メールサーバー:通知用の共有SMTP
  • 監視:統一されたログとメトリクス
  • バックアップ:一元化されたバックアップ戦略

まとめ

Windmillのセルフホスティングは、クラウドホスティングコストのごく一部で企業向けのワークフロー自動化を提供します。成功の鍵は、PostgreSQLの認証情報がどのように渡され、永続化されるかを理解し、インストールを妨げる可能性のあるURLエンコードの問題を回避するために16進数のみのパスワードを使用することです。

このセットアップの主な利点

  • コスト効率:クラウドソリューションと比較して年間数百ドルを節約
  • 本番対応:企業のワークロードを確実に処理
  • 安全:HTTPS、データベースポートの非公開、リソース制限
  • 拡張性:必要に応じてワーカーとリソースを簡単に追加
  • プライバシー:ワークフローから外部サービスへ送信しない限り、コードとデータは自分のインフラ内にとどまる

この設定は本番環境でテスト済みであり、事業に不可欠なワークフロー自動化に必要な信頼性を提供します。トラブルシューティングの手順は、デプロイ中に発生した実際の問題、特に多くのセルフホスト型環境に影響するPostgreSQL認証の問題に対処しています。

複雑なワークフローや企業向けのデプロイでは、用途に合った最適化と適切なリソース配分について、専門家への相談をご検討ください。

次のステップ

  • Windmillにも適用できるWebhookのトラブルシューティング手法を確認
  • 大規模データセットの処理に向けたペイロード最適化を確認
  • 既存のn8n環境との連携を検討

tvaについて

tvaは、データベースシステム、クラウド環境、グローバルサプライチェーンの包括的なインフラ管理を担っています。当社の体系的なアプローチは、厳格なセキュリティプロトコルとパフォーマンス最適化を組み合わせ、戦略的アドバイザリーサービスにより、デジタル機能と物理的資産の両方を的確に連携させ、すべての支援案件で最高水準の運用品質とコンプライアンスを維持しています。

当社のサービスおよび追加の自動化チュートリアルの詳細については、tva.sgをご覧ください。

設定作業から運用判断へ

実務上の問いは、プラットフォームを設定できるかどうかではありません。チームが責任の所在を説明し、構成のずれを検出し、場当たり的な対応なしに復旧し、狙った成果を変更によって改善できたと示せるかです。そのため、各変更に責任者、ベースライン、ロールバック手順、確認期間を組み合わせます。これにより、単発の修正が運用能力になります。本番環境での変更記録には、変更の理由、確認した証拠、正確な対象範囲、停止または取り消しを行う権限を持つ担当者を含めます。リリース後は、合意した指標をベースラインと比較し、結果を変更記録とともに保存します。期待した改善がなければ、ロールバックも妥当な結果であり、失敗ではありません。この運用管理は、個々の設定値よりも重要です。同じ記録が次の担当者に信頼できる出発点を与え、その後の最適化を、新たな推測ではなく測定に基づく判断に変えます。

関連記事

関連記事