Ubuntu+Mosquitto+Docker+WEB+WordPress+Python設定手順

■1:目標
・サーバPCにてUbuntu26.04とアプリを極力GUIで運用
・サーバPCはLANに有線接続
・サーバPC起動時にMosquittoを起動
・Dockerを構築、DockerをGUIで操作
・Docker内にてWEBサーバ、PHP、DBMSを構築、動作
・Docker内にてpython3、仮想環境を構築、動作
・Docker内にてWordPressを構築、動作

・他PCへまるごと移植

■2:環境設計値

2−1:開発PC
・mac-mini M1
・macOS Tahoe 26.6.2

2−2:サーバPC
・GMKTEC Nucbox N5105 / 8GB RAM / 250GB SSD
・Ubuntu 26.04 LTS Desktop
・Ethernet:enp1s0
・固定IPアドレス:192.168.10.24
・ネットマスク:255.255.255.0
・ゲートウェイ:192.168.10.24
・DNS:192.168.10.24

2−3:アプリ構成1(OS上)
・Desktop
・Mosquitto:OS起動時自動起動
・DockerDesk

2−4:アプリ構成2(Docker内)
・プロジェクト名:my-project
・WordPress、使用ポート=8080
・mariaDB
・PHP、phpAdmin
・WEBserver
・python3.14
・python仮想環境:my-env
・python外部ライブラリ:Frask

■3:Ubuntu26.04設置

3−1:開発PC上で公式からUbuntu26.04のISOファイルをダウンロード
  ・URL 
  ・「amd64」を選択

3−2:開発PCにRufusをインストール

 

3−3:Rufusで8GB以上のUSBフラッシュメモリにISOを書き込み
出典:https://ubuntu.fan/ja/docs/guide/installation/create-usb
・ブートの選択:

  [選択] をクリックして、ダウンロードした Ubuntu ISO ファイルを選択
・パーティションスキーム:
  ターゲットコンピューターが UEFIを使用している場合

   (2015 年以降のほとんどのコンピューター)、「GPT」を選択
  古い BIOS モードを使用している場合は「MBR」を選択
・ターゲット システム: パーティション スキームに対応

    UEFI の場合は、UEFI (非 CSM) を選択します
・残りのオプションはデフォルトのままにしておく。
・START をクリックし、書き込みが完了するまで待つ。
・書込は長時間を要する。プログレスバーで進捗確認する。
・プログレスバーが消えたら終了。書込完了という表示はない。
・ Rufus が ISO 書き込みモードについて尋ねるダイアログを表示した場合、
 「ISO イメージ モードで書き込み (推奨)」を選択する。


3−4:サーバPCでUSBフラッシュメモリを起動
  ・BIOSでUSB起動を設定
  ・ログインIDとパスワード設定
  ・インストール完了したら再起動。UDBフラッシュメモリを抜く。

■4:Mosquitto設置

4−1:Mosquittoインストール
・Ubuntu 26.04 のリポジトリからネイティブインストールし、

 LAN内からの接続を許可します。
sudo apt update
sudo apt install -y mosquitto mosquitto-clients

4−2. LAN内からの匿名接続を許可する設定ファイルを新規作成
sudo gnome-text-editor /etc/mosquitto/conf.d/local.conf
# ---------------------------------------------------------------------------
# すべてのインターフェース(LAN内)からの接続を1883番ポートで待ち受ける
listener 1883 0.0.0.0
allow_anonymous true
# ----------------------------------------------------------------------------

4−3. 再起動して自動起動を有効化
sudo systemctl restart mosquitto
sudo systemctl enable mosquitto

4−4:Mosquitto起動、停止、再起動
・システムの起動  sudo systemctl start mosquitto
・システムの状態確認  sudo systemctl status mosquitto
・システムの終了  sudo systemctl stop mosquitto


■5:Docker設置

5−1:Dockerインストール
出典:Ubuntu26.04 へ Docker Engine 一式をインストール
https://qiita.com/kujiraza/items/b3064a764ab9ce52650e
↑この手順でやればできる。以下、引用編集。

(5-1-1)現存Dockerがあれば停止、削除
sudo apt remove $(dpkg --get-selections docker.io docker-compose docker-compose-v2 docker-doc docker-buildx podman-docker containerd runc | cut -f1)

(5-1-2) 依存パッケージインストール
sudo apt update
sudo apt install ca-certificates curl

(5-1-3) Dockerリポジトリの公開鍵をUbuntu推奨ディレクトリへ格納
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
  -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc  # おそらく不要。念のため

(5-1-4) Dockerリポジトリ登録(deb822形式)
sudo tee /etc/apt/sources.list.d/docker.sources <<EOF
Types: deb
URIs: https://download.docker.com/linux/ubuntu
Suites: $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}")
Components: stable
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/docker.asc
EOF

(5-1-5) Docker Engine 最新版のインストール
sudo apt update
sudo apt install docker-ce docker-ce-cli \
  containerd.io docker-buildx-plugin docker-compose-plugin

(5-1-6)コンソール上で動作確認
ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
$ docker --version
Docker version 29.8.0, build 88096ef
$ sudo docker run hello-world
(最初にエラーが表示されることがあるが、無視)
...
Hello from Docker!
This message shows that your installation appears to be working correctly.
...
$ docker compose version
Docker Compose version v5.5.1
ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー

5−2:DockerDeskインストール



■6:Docker開発環境構築

6−1:directory構造

ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
my-project/
├── compose.yaml          # コンテナ全体の一元管理設定(Python、WP、DB)
├── app/                  # 【Python領域】
│   └── Dockerfile        # Python 3.14環境の設計図
├── wordpress/            # 【WordPress領域】
│   ├── Dockerfile        # Webサーバー(Apache)+ PHP + WPの設定
│   └── wp-content/       # 投稿画像、テーマ、プラグインが自動保存されるフォルダ
└── db_data/              # 【データベース領域 ★新規】
              # MariaDBのデータ(記事本文、設定、ユーザー情報)が自動保存される
ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
※ wp-content と db_data フォルダはコンテナ起動時にDockerが自動生成するため、
 最初は空のフォルダでよい(作成しなくても自動で作られる)。


6−2:compose.yaml の作成
3つのコンテナ(Python開発、WordPress、MariaDB)の結合を定義する。

# ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
services:
  # 1. Python 3.14 開発環境
  app:
    build: ./app
    container_name: python-dev-env
    volumes:
      - ./app:/workspace
    stdin_open: true
    tty: true

  # 2. WordPress環境(Webサーバー・PHP内蔵)
  wordpress:
    build: ./wordpress
    container_name: wp-web
    ports:
      - "8080:80"           # 外部PCからは http://<サーバのIP>:8080 でアクセス
    restart: always
    environment:
      WORDPRESS_DB_HOST: db
      WORDPRESS_DB_USER: wp_user
      WORDPRESS_DB_PASSWORD: wp_password
      WORDPRESS_DB_NAME: wordpress
    volumes:
      - ./wordpress/wp-content:/var/www/html/wp-content

  # 3. データベース環境(MariaDB)
  db:
    image: mariadb:latest
    container_name: wp-db
    restart: always
    environment:
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wp_user
      MYSQL_PASSWORD: wp_password
      MYSQL_ROOT_PASSWORD: root_password
    volumes:
      # 【重要】DBのデータをプロジェクト内の「db_data」ディレクトリに同期
      - ./db_data:/var/lib/mysql
# ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー

6−2:個々のDockerのためのDockerfile作成

(6-2-1)指定バージョンのpythonを含むapp/Dockerfile作成
cd my-project/app/
sudo gnome-text-editor
# ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
# ベースとなるPythonの公式イメージを指定
FROM python:3.14-slim
# コンテナ内の作業ディレクトリを設定
WORKDIR /app
# 必要な外部ライブラリがある場合はここでインストール
# RUN pip install --no-cache-dir pandas requests
# コンテナ起動時に実行するコマンド(例:対話型シェルを起動)
CMD ["python"]
# ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
ファイル名: Doclerfileで保存

(6-2-1)WordPressのためのwordpress/Dockerfile作成
cd my-project/wordpress/
sudo gnome-text-editor

# ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
# 1. WordPress公式最新イメージ(PHPとApache Webサーバー内蔵)がベース
FROM wordpress:latest
# 2. WordPressのプラグインや追加パッケージ・PHP拡張をインストール
RUN apt-get update && apt-get install -y \
    libpng-dev \
    libjpeg-dev \
    libwebp-dev \
    zip \
    unzip \
    && rm -rf /var/lib/apt/lists/* \
    && docker-php-ext-configure gd --with-jpeg --with-webp \
    && docker-php-ext-install -y gd mysqli pdo_mysql

# 3. 必要に応じて独自の php.ini 設定を適用(アップロードサイズ上限変更など)
# COPY php.ini /usr/local/etc/php/conf.d/custom.ini

# 4. タイムゾーンを日本時間に設定
ENV TZ=Asia/Tokyo

# 5. コンテナ起動時にWeb(Apache)が立上がる設定(ベースイメージから継承)
CMD ["apache2-foreground"]
# ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
ファイル名: Doclerfileで保存

↑補足説明:
WordPressの動作に必要な PHP、Apache(Web)、拡張張モジュール

(MySQL接続用など) は、公式ベースイメージにあらかじめすべて

インストールされている。この Dockerfile では、一般的なカスタマイズ

(画像処理ライブラリ WPMU などの追加や、日本時間への設定)を
自動で行う手順を記述している。


6−3:Dockerイメージビルドとコンテナ起動
# プロジェクトのルート(my-project/)で実行
cd my-project
docker compose up -d --build
docker build -t my-python-env .
docker run -it my-python-env


■7:python環境構築
1:仮想環境設置
2:外部ライブラリ設置
3:コード設定、試運転
4:Frisk環境

■8:WordPress環境構築
1:Docker開発環境内にWordPressインストール
2:LAN内の開発PCからサーバPCへリモート接続
3:開発PCからリモートでWordPress設定
4:WordPressでBlogを構築、起動

■9:IPアドレスの異なるサーバPCへのDockerまるごと移植
9−1:my-projectフォルダをまるごとUSBフラッシュメモリにコピー
9−2:移植先のサーバにmy-projectをペースト
9−3:ターミナルでDockerを起動
cd my-project
docker compose up -d

■10:初期設定後の重要な調整ポイント

Dockerでホスト側のディレクトリ(wordpress/wp-content や db_data)をバインドマウント(同期)する際、
Linux(Ubuntu)環境では、コンテナ内のユーザーとホストOSのユーザーの権限(UID/GID)が一致せず、
ファイルの読み書きや書き換えができないエラー(Permission Denied)が頻発します。
このエラーの根本的な対策は以下です。

## 1. 初期フォルダ生成時のファイル権限(Permission)エラー対策

WordPressやMariaDBの公式イメージは、セキュリティのためにコンテナ内部で

一般ユーザー(www-data や mysql)として動作します。

そのため、ホストOS側で root 権限でフォルダが作られてしまうと、

コンテナ側から書き込みができなくなります。
これを防ぐための2つの対策があります。

## 対策A:コンテナ起動後にホスト側で所有者を一括変更(最も簡単・確実)


コンテナを初回起動(docker compose up -d)すると、自動的にホスト側に wordpress/wp-content と db_data が生成されます。
生成された直後に、ホストOS(Ubuntu)側で以下のコマンドを実行し、コンテナ内のユーザーが読み書きできる適切な権限を付与します。

# プロジェクトのルートディレクトリ (my-project/) で実行
# WordPress用のフォルダ権限変更 (www-dataのUIDである33に変更)
sudo chown -R 33:33 ./wordpress/wp-content
# MariaDB用のフォルダ権限変更 (mysqlのUIDである999に変更)
sudo chown -R 999:999 ./db_data
これを行うことで、WordPressのプラグインインストール時や、データベースのデータ更新時に
「書き込み権限がありません」というエラーが出るのを完全に防げます。

## 対策B:compose.yaml で実行ユーザーを指定する


MariaDBに関しては、compose.yaml に user: "1000:1000"

(あなたのUbuntuのユーザーID)を指定して、
ホストOSのユーザー権限でデータベースを起動させる方法もあります。

ただし、WordPress公式イメージは内部でポート80番(管理者権限が必要)

を開く仕様上、この指定を行うと起動エラーになることがあるため、
対策Aの chown コマンドによる所有者変更が最も安全です。
------------------------------

■Pythonからデータベース(MariaDB)へ接続してデータを読み書きする

 具体的な実装例

## 2. PythonからMariaDB(db_data)へ接続して読み書きするコード例
Python開発用コンテナ(app)から、同じDockerネットワーク内にある db コンテナ(MariaDB)に接続し、WordPressのデータを読み書きするコードを作成します。
## ① VS Codeのターミナルで必要なライブラリをインストール
PythonからMariaDB(MySQL)を操作するために、最も一般的で軽量な PyMySQL ライブラリを使用します。VS Codeでコンテナに接続した状態のターミナルで、以下を実行します。

pip install pymysql

## ② Pythonコード(app/src/main.py)の実装
WordPressのデータベース構造にアクセスし、

投稿されている記事のタイトル一覧を取得(読み込み)したり、

新しくデータを挿入(書き込み)したりするサンプルコードです。

import pymysqlimport time
# データベースの接続設定# Docker Composeの特性上、
# host名にはIPアドレスではなくサービス名の「db」を指定できます

DB_CONFIG = {
    "host": "db",
    "user": "wp_user",
    "password": "wp_password",
    "database": "wordpress",
    "charset": "utf8mb4",
    "cursorclass": pymysql.cursors.DictCursor
}

def connect_db():
    """データベースが起動するまで接続を試行する関数"""
    while True:
        try:
            connection = pymysql.connect(**DB_CONFIG)
            return connection
        except pymysql.MySQLError:
            print("データベースの起動を待っています...")
            time.sleep(2)

def main():
    connection = connect_db()
    try:
        with connection.cursor() as cursor:
            print("--- 1. WordPressの投稿一覧(タイトル)を読み込む ---")
            # wp_postsはWordPressが自動生成する記事保存テーブルです
            sql_select = "SELECT ID, post_title, post_status FROM wp_posts WHERE post_type='post'"
            cursor.execute(sql_select)
            posts = cursor.fetchall()
            
            if not posts:
                print("まだ記事が投稿されていません。WordPressのリモート設定を完了させてください。")
            for post in posts:
                print(f"ID: {post['ID']} | タイトル: {post['post_title']} ({post['post_status']})")

            print("\n--- 2. 独自のテストテーブルを作成して書き込む ---")
            # Pythonアプリ専用のデータ保存テーブルを同じDB内に作成してみる例
            cursor.execute("""
                CREATE TABLE IF NOT EXISTS my_python_logs (
                    id INT AUTO_INCREMENT PRIMARY KEY,
                    message VARCHAR(255) NOT NULL,
                    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
                )
            """)
            
            sql_insert = "INSERT INTO my_python_logs (message) VALUES (%s)"
            cursor.execute(sql_insert, ("Pythonからデータを書き込みました!",))
            
            # データの変更を確定(コミット)
            connection.commit()
            print("データの書き込みに成功しました。")

    except pymysql.MySQLError as e:
        print(f"エラーが発生しました: {e}")
    finally:
        connection.close()
if __name__ == "__main__":
    main()

## 💡 この構成のメリット

・ホスト名に db を指定可能:
 Docker Composeのネットワーク機能により、IPアドレスが動的に変わっても、
 コンテナ名である db という名前で自動的に名前解決されます。
 ・データは ./db_data に即時反映:
 Pythonから書き込んだデータや作成したテーブルは、ホストOS上の ./db_data に
 即座に保存されます。そのため、コンテナを削除してもデータが消えることはなく、
 他PCへそのまま移植可能です。

これで「開発・権限対策・外部連携・移植」のすべてのパーツが揃いました!