QNAPのDockerで複数WordPressを分離構成に移行する方法【Nginx + Cloudflare Tunnel】

QNAPのDockerで複数WordPressを分離構成に移行する方法【Nginx + Cloudflare Tunnel】

2026年3月26日

はじめに

QNAPのContainerStationでDockerを使って複数のWordPressサイトを運用していると、最初は1つのdocker-compose.ymlにまとめた「統合構成」で始めることが多いです。

しかしサイト数が増えたり、管理者が異なるサイトを運用するようになると、1つのコンテナが止まると全サイトに影響するという問題が出てきます。

この記事では、統合構成からサイトごとに独立した分離構成への移行手順を解説します。

適宜自分の構成、サイト名など書き換えて使ってください。


統合構成と分離構成の違い

統合構成(移行前)

site_folder/
├── wordpress_site1
├── wordpress_site2
├── mariadb_site1
├── mariadb_site2
├── nginx_reverse_proxy  ← 全サイト共通
├── phpmyadmin
└── cloudflared          ← 全サイト共通

問題点:

  • 1サイトのコンテナ障害が全サイトに影響する
  • サイトが増えるとdocker-compose.ymlが肥大化する
  • 管理者が異なるサイトを同一ファイルで管理しにくい

分離構成(移行後)

shared/                  ← 新規作成
├── nginx_reverse_proxy  ← 全サイト共通
├── cloudflared          ← 全サイト共通
└── phpmyadmin

site1/                   ← WordPressとDBのみ
├── wordpress_site1
└── mariadb_site1

site2/                   ← WordPressとDBのみ
├── wordpress_site2
└── mariadb_site2

メリット:

  • 1サイトを停止しても他サイトに影響しない
  • サイトごとにdocker-compose.ymlが独立して管理しやすい
  • サイトの追加・削除が簡単

この記事でわかること

  • 共有ネットワークの作成方法
  • NginxとCloudflaredをsharedフォルダに分離する方法
  • 各サイトのdocker-compose.ymlをWordPress+DBのみに縮小する方法
  • 移行時に起きやすいトラブルと解決方法

環境

  • QNAP NAS(ContainerStation インストール済み)
  • SSH接続ソフト:TeraTerm
  • 運用中サイト:2サイト(your-site1.com、your-site2.com)
  • 共通コンテナ:Nginx、Cloudflare Tunnel、phpMyAdmin

事前準備

バックアップを取る

必ずバックアップを取ってから作業してください。WordPressのファイルとデータベースの両方が必要です。

SSHを有効にする

SSHの有効化手順はこちら [QNAPのCloudflaredをSSHでアップデートする方法]


Step 1:共有ネットワークを作成する

全コンテナが通信できる共有ネットワークを作成します。これはサイトに影響しない安全な作業です。

docker network create shared_proxy

実行結果:

04886ddca261d315fbcaxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
docker network create shared_proxy コマンドの実行結果。共有ネットワーク作成後に表示されるハッシュ文字列のSSH画面

Step 2:sharedフォルダを作成する

NginxとCloudflaredを管理するsharedフォルダを作成します。

mkdir -p /share/CACHEDEV4_DATA/docker/shared/nginx/conf.d
mkdir -p /share/CACHEDEV4_DATA/docker/shared/cloudflared
mkdir -p /share/CACHEDEV4_DATA/docker/shared/certs
mkdir コマンドで shared/nginx/conf.d、cloudflared、certs フォルダを作成したSSH画面

Step 3:設定ファイルをコピーする

既存の設定ファイルをsharedフォルダにコピーします。

cp /share/CACHEDEV4_DATA/docker/your_app/nginx/nginx.conf \
   /share/CACHEDEV4_DATA/docker/shared/nginx/nginx.conf

cp /share/CACHEDEV4_DATA/docker/your_app/nginx/conf.d/*.conf \
   /share/CACHEDEV4_DATA/docker/shared/nginx/conf.d/

cp /share/CACHEDEV4_DATA/docker/your_app/cloudflared/config.yml \
   /share/CACHEDEV4_DATA/docker/shared/cloudflared/config.yml

cp /share/CACHEDEV4_DATA/docker/your_app/cloudflared/credentials.json \
   /share/CACHEDEV4_DATA/docker/shared/cloudflared/credentials.json

cp /share/CACHEDEV4_DATA/docker/your_app/certs/* \
   /share/CACHEDEV4_DATA/docker/shared/certs/
cp コマンドで nginx.conf・cloudflared・certs などの設定ファイルを shared フォルダにコピーしたSSH画面

コピーされたか確認します:

ls /share/CACHEDEV4_DATA/docker/shared/nginx/conf.d/
ls /share/CACHEDEV4_DATA/docker/shared/cloudflared/
ls /share/CACHEDEV4_DATA/docker/shared/certs/

ls コマンドで shared/nginx/conf.d、cloudflared、certs にファイルがコピーされたことを確認するSSH画面

Step 4:shared用docker-compose.ymlを作成する

vimやnanoで作成しても構いません。

cat > /share/CACHEDEV4_DATA/docker/shared/docker-compose.yml << 'EOF'
services:
  nginx_reverse_proxy:
    container_name: nginx_reverse_proxy_shared
    image: nginx:latest
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
      - ./certs:/etc/certs:ro
      - ./nginx/conf.d:/etc/nginx/conf.d:ro
    networks:
      - shared_proxy

  cloudflared:
    image: cloudflare/cloudflared:latest
    container_name: cloudflared_shared
    restart: unless-stopped
    command: tunnel --config /etc/cloudflared/config.yml run your-tunnel-name
    volumes:
      - ./cloudflared/config.yml:/etc/cloudflared/config.yml:ro
      - ./cloudflared/credentials.json:/etc/cloudflared/credentials.json:ro
    networks:
      - shared_proxy

  phpmyadmin:
    image: phpmyadmin:latest
    container_name: phpmyadmin
    restart: always
    ports:
      - "8081:80"
    environment:
      PMA_HOST: mariadb_site1
    networks:
      - shared_proxy

networks:
  shared_proxy:
    external: true
EOF
cat コマンドで shared 用 docker-compose.yml(nginx、cloudflared、phpmyadmin サービス定義)を作成したSSH画面

⚠️ 重要:config.ymlのcommandにも--configオプションを追加する tunnel run your-tunnel-nameだけではconfig.ymlが読み込まれません。 必ずtunnel --config /etc/cloudflared/config.yml run your-tunnel-nameと記述してください。


Step 5:既存ファイルをバックアップする

既存のdocker-compose.ymlを書き換える前にバックアップを取ります。

cp /share/CACHEDEV4_DATA/docker/your_app/docker-compose.yml \
   /share/CACHEDEV4_DATA/docker/your_app/docker-compose.yml.bak
cp コマンドで既存の docker-compose.yml を .bak ファイルとしてバックアップしたSSH画面

Step 6:site1のdocker-compose.ymlをWordPress+DBのみに縮小する

cat > /share/CACHEDEV4_DATA/docker/site1/docker-compose.yml << 'EOF'
services:
  mariadb_site1:
    image: mariadb:10.11
    container_name: mariadb_site1
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: your_root_password
      MYSQL_DATABASE: your_database
      MYSQL_USER: your_user
      MYSQL_PASSWORD: your_password
    volumes:
      - ./db_data:/var/lib/mysql
    networks:
      - shared_proxy

  wordpress_site1:
    image: wordpress:php8.2-apache
    container_name: wordpress_site1
    restart: unless-stopped
    environment:
      WORDPRESS_DB_HOST: mariadb_site1
      WORDPRESS_DB_USER: your_user
      WORDPRESS_DB_PASSWORD: your_password
      WORDPRESS_DB_NAME: your_database
    volumes:
      - ./html:/var/www/html
    networks:
      - shared_proxy

networks:
  shared_proxy:
    external: true
EOF
cat コマンドで site1 用 docker-compose.yml(mariadb と wordpress のみ)を作成したSSH画面

site2も同様に作成します。


Step 7:切り替え作業(ダウンタイムあり)

ここからは数分のダウンタイムが発生します。

旧コンテナを停止

cd /share/CACHEDEV4_DATA/docker/your_app
docker compose down

新コンテナを起動(site1)

cd /share/CACHEDEV4_DATA/docker/site1
docker compose up -d
docker compose up -d で site1 コンテナを起動した際の実行結果(Container が Started 表示)のSSH画面

新コンテナを起動(site2)

旧コンテナが残っている場合はエラーが出ることがあります:

Error response from daemon: Conflict. The container name "/mariadb_site2" is already in use

その場合は旧コンテナを削除してから起動します:

docker rm -f mariadb_site2 wordpress_site2
docker compose up -d

sharedを起動

cd /share/CACHEDEV4_DATA/docker/shared
docker compose up -d

ポート80が既存のNginxに使われている場合はエラーが出ます:

Bind for 0.0.0.0:80 failed: port is already allocated

旧Nginxを削除してから再起動します:

docker rm -f nginx_reverse_proxy
docker compose up -d

Step 8:動作確認

全コンテナが起動しているか確認します:

docker ps --format "table {{.Names}}\t{{.Status}}"
docker ps コマンドで全コンテナの名前と起動状態(Up)を一覧表示したSSH画面

各サイトにアクセスして表示を確認してください。


トラブルシューティング

502 Bad Gateway が出る

原因①:config.ymlのコンテナ名が古いまま

config.ymlのserviceに旧コンテナ名が残っている場合に発生します。

# 修正前(古い名前)
service: https://nginx_reverse_proxy:443

# 修正後(新しい名前)
service: https://nginx_reverse_proxy_shared:443

修正後にCloudflaredを再起動します:

cd /share/CACHEDEV4_DATA/docker/shared
docker compose up -d --force-recreate cloudflared

原因②:旧cloudflaredコンテナが生き残っている

旧コンテナが残っているとリクエストを横取りされます。

docker ps | grep cloudflared

旧コンテナが残っている場合は削除します:

docker stop cloudflared
docker rm cloudflared

--remove-orphansでphpmyadminが消えた

docker compose up -d --remove-orphansを実行すると、新しいdocker-compose.ymlに含まれていないコンテナが削除されます。

phpmyadminをshared/docker-compose.ymlに追加して再起動することで復旧できます。

起動後に「その他」状態から変わらない

ブラウザをF5で更新すると「実行中」に変わります。


まとめ

今回実施したコマンドをまとめます:

# 1. 共有ネットワーク作成
docker network create shared_proxy

# 2. フォルダ作成
mkdir -p /share/CACHEDEV4_DATA/docker/shared/nginx/conf.d
mkdir -p /share/CACHEDEV4_DATA/docker/shared/cloudflared
mkdir -p /share/CACHEDEV4_DATA/docker/shared/certs

# 3. 設定ファイルコピー
cp -r /share/CACHEDEV4_DATA/docker/your_app/nginx/nginx.conf \
      /share/CACHEDEV4_DATA/docker/shared/nginx/
cp /share/CACHEDEV4_DATA/docker/your_app/nginx/conf.d/*.conf \
   /share/CACHEDEV4_DATA/docker/shared/nginx/conf.d/
cp /share/CACHEDEV4_DATA/docker/your_app/cloudflared/* \
   /share/CACHEDEV4_DATA/docker/shared/cloudflared/
cp /share/CACHEDEV4_DATA/docker/your_app/certs/* \
   /share/CACHEDEV4_DATA/docker/shared/certs/

# 4. 旧コンテナ停止
cd /share/CACHEDEV4_DATA/docker/your_app
docker compose down

# 5. 新コンテナ起動
cd /share/CACHEDEV4_DATA/docker/site1 && docker compose up -d
cd /share/CACHEDEV4_DATA/docker/site2 && docker compose up -d
cd /share/CACHEDEV4_DATA/docker/shared && docker compose up -d

# 6. 確認
docker ps --format "table {{.Names}}\t{{.Status}}"

関連記事