2026年9月12日土曜日

自宅ネットワークを構築する

スイッチングハブが届いたので、自宅ネットワークの構築を始めた。

目標の構成

目標の構成は次のとおり。

BUFFALO WSR-1500AX2S-BK の動作確認

押し入れから引っ張り出してきた BUFFALO WSR-1500AX2S-BK の動作確認から始める。

モード切替スイッチをルーターモードにして電源を接続し、リセットボタンを押す。

ルーター本体に書いてある SSID とパスワードで、ルーターの LAN に接続する。

ルーターの初期設定

http://192.168.11.1/login.html にアクセスし、本体に記載のユーザー名とパスワードでログインする。

設定画面 から 詳細設定 を開く。

Internet の設定

まず Internet の設定をする。

今回は宅内 LAN の増設なので、DHCP を有効にするだけでよい。

LAN の設定

次に LAN の設定をする。

デフォルトからの変更点は次のとおりだ。

  • LAN側IPアドレス: 192.168.2.1

ルーターの IP アドレスと LAN のネットワークアドレスが変わったので、一度 PC の Wi-Fi を OFF にして接続し直す。

http://192.168.2.1/login.html にアクセスし、もう一度詳細設定画面を開く。

無線の設定

バンドステアリング Lite を OFF にする。

2.4 GHz 帯を OFF にする。

5 GHz 帯の設定をする。

各マシンのネットワーク設定

母艦 PC はもともと DHCP なので、物理的につなげるだけでよい。

gx10-707e.local の設定

有線の定義を /etc/netplan/50-ether.yaml に書く。

network:
  version: 2
  ethernets:
    enP7s7:
      dhcp4: false
      addresses:
        - 192.168.2.254/24
      routes:
        - to: default
          via: 192.168.2.1
      nameservers:

無線を無効化する。

sudo nmtui を実行し、接続の編集 から対象の SSID を選び、自動的に接続する のチェックを外す。

gx10-6acc.local の設定

有線の定義を /etc/netplan/50-ether.yaml に書く。

network:
  version: 2
  ethernets:
    enP7s7:
      dhcp4: false
      addresses:
        - 192.168.2.253/24
      routes:
        - to: default
          via: 192.168.2.1
      nameservers:

無線を無効化する。

sudo nmtui を実行し、接続の編集 から対象の SSID を選び、自動的に接続する のチェックを外す。

申し送り事項

ネットワーク構成の更新は完了した。

申し送り事項は次のとおりだ。

  1. 母艦 PC のケーブルが 2.5G
    • 調達した 10G ケーブルの長さが足りませんでした…
  2. 無線ガジェットはまだ以前の SSID に接続中
    • 設定が面倒なので必要に応じて徐々に移行
  3. 何か使っているルーターの調子が悪い
    • もしかしたら買い替え必要かも?

「3.」以外は明日以降、順次解消していく。

参考資料

DGX Spark をデジタルフォトフレーム化する

DGX Spark(GX10)にデジタルフォトフレーム機能を追加する作業を記録をまとめた。

結果だけ見たい方は mikoto2000/dgx-spark-photoframe: GUI 無しの DGX Spark をデジタルフォトフレーム化するモノ を参照。

目標

まず目標の確認から。

  1. 15 秒ごとに photo ディレクトリ以下の画像をディスプレイに表示したい
  2. 表示はフルスクリーンで
  3. X, Wayland は使いたくない
  4. 電源 ON にしたら自動でフォトフレーム機能を実行してほしい

現状確認

次は現状確認。

現状はこのブログの手順を実行した直後という感じ。

  • https://mikoto2000.blogspot.com/2026/09/dgx-sparkasus-ascent-gx10.html
  • https://mikoto2000.blogspot.com/2026/09/dgx-sparkasus-ascent-gx102-deepseek-v4.html

USB-C モニタが認識されない問題に遭遇

USB-C のモニタを接続したが、認識してくれない。原因を調査していく。

この不具合に当たっている。

対応策は sudo apt purge nvidia-drm-options-modeset0 らしい。試してみる。

モニタの回路から完全に電源を抜かなければならない。

sudo apt purge nvidia-drm-options-modeset0 してから poweroff して、GX10 の電源ケーブルを抜いて 1 分程度待ってから電源をつける。

無事モニタが認識され、ログインプロンプトが表示された。

フォトフレーム機能の実装

なんかファイルを作ってばかりで進捗をツイートしにくい。

デジタルフォトフレーム機能のための Dockerfile と compose.yaml を作っている。

Dockerfile

まず Dockerfile はこれ。シンプルに mpv だけインストールした Ubuntu 環境。

FROM ubuntu:24.04

ENV DEBIAN_FRONTEND=noninteractive

RUN apt-get update \
    && apt-get install -y --no-install-recommends \
       mpv \
    && rm -rf /var/lib/apt/lists/*

COPY entrypoint.sh /entrypoint.sh

RUN chmod +x /entrypoint.sh

ENTRYPOINT ["/entrypoint.sh"]

entrypoint.sh

次は entrypoint.sh。指定された写真フォルダ内の画像を再帰的に探して mpv に渡す。

#!/bin/bash

# コマンド実行時にエラーが発生したら即終了する。
# 未定義変数の参照や、パイプ途中のコマンド失敗もエラーとして扱う。
set -euo pipefail

# /photos 配下から表示対象の画像ファイルを検索し、
# mpv 用のプレイリストを生成する。
#
# 対象形式:
# - JPEG
# - PNG
# - WebP
#
# ファイル名に空白などが含まれていても扱えるよう、
# find では NULL 区切りで取得している。
find /photos \
  -type f \
  \( \
    -iname '*.jpg' -o \
    -iname '*.jpeg' -o \
    -iname '*.png' -o \
    -iname '*.webp' \
  \) \
  -print0 \
  | sort -z \
  | tr '\0' '\n' \
  > /tmp/photos.m3u

# 表示対象の画像が1枚も存在しない場合は、
# mpv を起動せずエラー終了する。
if [ ! -s /tmp/photos.m3u ]; then
  echo "表示可能な画像が /photos に存在しません。" >&2
  exit 1
fi

# mpv を起動し、DRM/KMS を利用して
# デスクトップ環境を介さずモニタへ直接描画する。
#
# DRM_CONNECTOR:
#   使用する DRM connector。
#   例: DP-1
#   未指定の場合は DP-1。
#
# PHOTO_DURATION:
#   1枚の写真を表示する秒数。
#   未指定の場合は15秒。
#
# PHOTO_ROTATE:
#   写真を回転して表示する角度。
#   0 / 90 / 180 / 270 を想定。
#   未指定の場合は0度。
#
# --loop-playlist=inf:
#   最後の写真まで表示したら先頭へ戻り、
#   スライドショーを無限に繰り返す。
#
# exec を使用することで mpv 自体をコンテナの PID 1 とし、
# docker stop などのシグナルを直接受信できるようにする。
exec mpv \
  --vo=drm \
  --drm-device="${DRM_DEVICE:-/dev/dri/card1}" \
  --drm-connector="${DRM_CONNECTOR:-DP-1}" \
  --drm-mode=preferred \
  --video-rotate="${PHOTO_ROTATE:-0}" \
  --profile=sw-fast \
  --fullscreen \
  --no-audio \
  --image-display-duration="${PHOTO_DURATION:-15}" \
  --loop-playlist=inf \
  --playlist=/tmp/photos.m3u

compose.yaml

次は compose.yaml。.env を読み込んでさっきの Dockerfile のイメージを起動する。

services:
  photoframe:
    build:
      context: .

    container_name: dgx-spark-digital-photoframe

    restart: unless-stopped

    devices:
      - "${DRM_DEVICE:-/dev/dri/card1}:${DRM_DEVICE:-/dev/dri/card1}"

    volumes:
      - "${PHOTO_DIR:-./photos}:/photos:ro"

    environment:
      DRM_DEVICE: "${DRM_DEVICE:-/dev/dri/card1}"
      DRM_CONNECTOR: "${DRM_CONNECTOR:-DP-1}"
      PHOTO_DURATION: "${PHOTO_DURATION:-15}"
      PHOTO_ROTATE: "${PHOTO_ROTATE:-0}"

.env(.env.example)

最後に .env(.env.example)。

写真ディレクトリ、出力デバイス、表示秒数、回転角度を指定できる。

# ホスト側の写真ディレクトリ。
# コンテナ内では /photos として読み取り専用でマウントされる。
PHOTO_DIR=~/photos

# 使用する DRM デバイス。
#
# 利用可能な DRM デバイスは、ホスト側で次のコマンドを実行して確認できる。
#
#   ls -l /dev/dri/
#
# 例:
#   card1
#   renderD128
#
# この場合は /dev/dri/card1 を指定する。
DRM_DEVICE=/dev/dri/card1

# 使用する DRM connector。
#
# 接続中の connector は、ホスト側で次のコマンドを実行して確認できる。
#
#   grep -H connected /sys/class/drm/card*-*/status
#
# 例:
#   /sys/class/drm/card0-DP-1/status: connected
#   /sys/class/drm/card0-DP-2/status: disconnected
#
# この場合は DP-1 を指定する。
DRM_CONNECTOR=Unknown-4

# 1枚の写真を表示する時間(秒)。
PHOTO_DURATION=15

# 写真の回転角度。
# 0 / 90 / 180 / 270 を指定する。
# モニタを縦置きする場合は 90 または 270 を指定する。
PHOTO_ROTATE=0

起動

これで .env を書いて docker compose up -d すればモニタに画像が映る。

参考資料

2026年9月9日水曜日

DGX Spark(ASUS ASCENT GX10)2 台連結と DeepSeek V4 Flash Vision Exp セットアップ記録

前回 は 1 台のセットアップを記録した。

今回は 2 台を QSFP ケーブルで連結し、DeepSeek V4 Flash Vision Exp を動かすまでの手順を記録した。

1. QSFP ケーブルでの 2 台接続

まず QSFP ケーブルで 2 台の GX10 を接続する。

QSFP ケーブルを差すときは、有線 LAN ポートに近い方のポートを使う。 そうすると、後で行うインターフェースが、この記事で書かれているものと同じになるはず。

2. インターフェースの特定と固定 IP の割り当て

接続後、ibdev2netdev コマンドでインターフェースを確認する。

ibdev2netdev

以下のような出力になる。

roceP2p1s0f0 port 1 ==> enP2p1s0f0np0 (Up)
roceP2p1s0f1 port 1 ==> enP2p1s0f1np1 (Down)
rocep1s0f0 port 1 ==> enp1s0f0np0 (Up)
rocep1s0f1 port 1 ==> enp1s0f1np1 (Down)

Up となっているインターフェースに、それぞれ固定 IP を割り当てる。

GX10-1 では /etc/netplan/40-cx7.yaml を編集する。

network:
  version: 2
  ethernets:
    enp1s0f1np1:
      addresses:
        - 192.168.100.10/24
      dhcp4: no
    enP2p1s0f1np1:
      addresses:
        - 192.168.101.10/24
      dhcp4: no

GX10-2 では同じファイルに以下の内容を書く。

network:
  version: 2
  ethernets:
    enp1s0f1np1:
      addresses:
        - 192.168.100.11/24
      dhcp4: no
    enP2p1s0f1np1:
      addresses:
        - 192.168.101.11/24
      dhcp4: no

両方で設定を適用する。

sudo chmod 600 /etc/netplan/40-cx7.yaml
sudo netplan apply

ip addr show で、設定が正しく適用されていることを確認する。

3. パスワードレス SSH の設定

ノード間でパスワードレス SSH を行うための設定をする。

両方の GX10 でキーペアを作成する。

ssh-keygen -t ed25519

お互いに公開鍵を送信し合う。

GX10-1 から GX10-2 へ公開鍵を送信する。

ssh-copy-id 192.168.100.11

GX10-2 から GX10-1 へ公開鍵を送信する。

ssh-copy-id 192.168.100.10

ノード間通信を確実に QSFP ケーブルで行うため、hosts ファイルにエントリを追加する。

192.168.100.10 gx10-1
192.168.100.11 gx10-2

ここまでで連携の土台が完成する。

4. DeepSeek V4 Flash レシピの適用

次に、DeepSeek-v4-Flash-DSpark-2x-DGX-Spark のレシピを適用する。

GX10-1 で作業を開始する。

mkdir -p ~/project
cd project
git clone https://github.com/MiaAI-Lab/DeepSeek-v4-Flash-DSpark-2x-DGX-Spark.git

env ファイルを用意する。

cd DeepSeek-v4-Flash-DSpark-2x-DGX-Spark
cp .env.dspark.example .env.dspark
vim .env.dspark

以下を指定する。

WORKER_HOST=192.168.100.11
MASTER_ADDR=192.168.100.10

VLLM_HOST_IP=192.168.100.10
WORKER_VLLM_HOST_IP=192.168.100.11

GX10-2 のユーザーを docker グループに入れ忘れていたのが発覚したのでここで入れる。

sudo usermod -aG docker <ユーザー名>

両方の GX10 で Docker イメージを pull する。

docker pull ghcr.io/anemll/dspark-vllm-gx10:0.1.1

次にモデルをダウンロードする。GX10-1 で以下を実行する。

./prepare-dspark-model-cache.sh --official

しばらく待つと、GX10-1 と GX10-2 の両方にモデルがダウンロードされる。

5. サーバー起動と動作確認

これで準備が整ったので、サーバーを起動する。

./start-deepseek-v4-flash-dspark.sh

boot-shape-warmup: 47/47 requests ok in 77s のような文字列が表示され、コマンド実行が終われば起動完了である。

docker ps でコンテナが動いていることを確認する。

最後に、curl コマンドでチャットのエンドポイントにリクエストを送り、動作確認する。

ポート 8888 で待ち受けているので、以下のコマンドでリクエストを投げる。

curl http://localhost:8888/v1/chat/completions \
    -H 'Content-Type: application/json' \
    -d '{"model":"deepseek-v4-flash-vision-exp","messages":[{"role":"user","content":"Design a small rate"}]}'

応答の JSON が返却されれば OK.

あとは OpenAI 互換の好きなクライアントで接続すれば良い。

以上。

参考資料