Clone
1
環境構築手順
みてるぞ が 2026-09-06 20:33:06 +09:00 にこのページを編集

サーバー環境構築

概要

このページでは nizika_broadcast V1 を Ubuntu 26.04 LTS 上で稼働させるための環境構築手順を記載する。

現在の運用対象は V1。

nizika_broadcast_v2 は deprecated とし、今回の環境構築では使用しない。

本番構成:

nizika_broadcast
    │
    ├─ pygame
    ├─ nizika_ai
    ├─ nizika_nico
    │
    ├─ Xvfb :99
    │
    ├─ PulseAudio
    │    └─ stream
    │         └─ stream.monitor
    │
    ├─ AqKanji2Koe
    ├─ AquesTalk2 Eva
    │
    └─ ffmpeg
         │
         └─ YouTube RTMPS

repository:

/opt/nizika_broadcast

service user:

nizika

1. service user

useradd --system \
  --home /var/lib/nizika \
  --create-home \
  --shell /usr/sbin/nologin \
  nizika

確認:

id nizika

2. repository

信頼できる Gitea の最新 main を取得し、

/opt/nizika_broadcast

へ配置する。

旧サーバーの working directory をそのままコピーしない。

関連 repository:

/opt/nizika-nico

nizika_ai もコードおよび DB 接続上の依存として利用される。


3. OS package

apt update

apt install -y \
  git curl unzip \
  ffmpeg \
  xvfb \
  pulseaudio \
  pulseaudio-utils \
  python3 \
  python3-pip \
  python3-pygame \
  python3-opencv \
  python3-numpy \
  python3-ephem \
  python3-emoji

4. Python package

この環境では venv を使用せず system Python を使用する。

pip install 前:

umask 022
export HOME=/root

必要 package:

python3 -m pip install \
  --break-system-packages \
  'requests==2.32.5' \
  'pytchat==0.5.5' \
  'httpx[http2]==0.27.2' \
  pydub \
  audioop-lts \
  simplejson \
  'eloquent==0.5' \
  'mysqlclient==2.2.8'

5. Python 3.14 の注意

Python 3.14 では標準 audioop が削除されている。

pydub を利用するため:

audioop-lts

を追加する。


6. pip permission の注意

pip install 時に umask 077 が設定されていると、

/usr/local/lib/python3.14/dist-packages

配下が:

drwx------
-rw-------

となる場合がある。

この状態では nizika user から package が正常に見えず、

No module named 'pytchat.core'
module 'httpx' has no attribute 'Client'

等の不可解な error が発生する場合がある。

確認:

find /usr/local/lib/python3.14/dist-packages \
  -type d ! -perm -005 -o -type f ! -perm -004 \
  -print \
  | head -100

必要なら:

chmod -R a+rX \
  /usr/local/lib/python3.14/dist-packages

7. Python import test

runuser -u nizika -- python3 - <<'PY'
mods = [
    "httpx",
    "pytchat",
    "pydub",
    "eloquent",
    "MySQLdb",
    "pygame",
    "cv2",
    "numpy",
]

for mod in mods:
    try:
        m = __import__(mod)
        print(f"{mod}: OK {getattr(m, '__file__', None)}")
    except Exception as e:
        print(f"{mod}: NG {type(e).__name__}: {e}")
PY

8. AqKanji2Koe

repository 内の:

aques

libAqKanji2Koe.so.4 を利用する。

旧サーバーの binary をコピーせず、A-Quest 公式 Linux package から取得する。

64bit library を /usr/local/lib へ配置する。

最終的に:

/usr/local/lib/libAqKanji2Koe.so.4.1
/usr/local/lib/libAqKanji2Koe.so.4
/usr/local/lib/libAqKanji2Koe.so

となるよう symlink を作成する。

反映:

ldconfig

動作確認:

cd /opt/nizika_broadcast

printf 'こんにちは\n' | ./aques

aques は WAV generator ではなく、漢字仮名交じり文から AquesTalk 用の音声記号列を生成する。


9. AquesTalk2 Eva

aques.py は:

libAquesTalk2Eva.so

を利用する。

A-Quest 公式 Linux evaluation package から取得する。

配置例:

/usr/local/lib/libAquesTalk2Eva.so.2.3
/usr/local/lib/libAquesTalk2Eva.so.2
/usr/local/lib/libAquesTalk2Eva.so

反映:

ldconfig

この環境では:

LD_LIBRARY_PATH=/usr/local/lib

も設定する。

確認:

LD_LIBRARY_PATH=/usr/local/lib \
python3 - <<'PY'
from ctypes import cdll

cdll.LoadLibrary('libAquesTalk2Eva.so')

print('libAquesTalk2Eva: OK')
PY

10. PulseAudio

directory:

mkdir -p /etc/nizika/pulse

chmod 755 \
  /etc/nizika \
  /etc/nizika/pulse

以下を作成:

/etc/nizika/pulse/default.pa

内容:

#!/usr/bin/pulseaudio -nF

load-module module-native-protocol-unix
load-module module-device-restore
load-module module-stream-restore
load-module module-card-restore
load-module module-augment-properties
load-module module-default-device-restore
load-module module-always-sink

load-module module-null-sink sink_name=stream sink_properties=device.description=StreamSink

set-default-sink stream
set-default-source stream.monitor

権限:

chmod 644 \
  /etc/nizika/pulse/default.pa

11. pulseaudio-headless.service

作成:

/etc/systemd/system/pulseaudio-headless.service

内容:

[Unit]
Description=Nizika virtual audio

[Service]
Type=simple
User=nizika
Group=nizika

Environment=HOME=/var/lib/nizika
Environment=XDG_RUNTIME_DIR=/run/nizika
Environment=PULSE_SERVER=unix:/run/nizika/pulse/native

RuntimeDirectory=nizika
RuntimeDirectoryMode=0700

ExecStart=/usr/bin/pulseaudio \
  --daemonize=no \
  --exit-idle-time=-1 \
  --log-target=journal \
  -nF /etc/nizika/pulse/default.pa

Restart=on-failure
RestartSec=2

[Install]
WantedBy=multi-user.target

反映:

systemctl daemon-reload

systemctl enable \
  pulseaudio-headless.service

systemctl start \
  pulseaudio-headless.service

確認:

systemctl --no-pager --full status \
  pulseaudio-headless.service

12. PulseAudio device 確認

sink:

runuser -u nizika -- env \
  HOME=/var/lib/nizika \
  XDG_RUNTIME_DIR=/run/nizika \
  PULSE_SERVER=unix:/run/nizika/pulse/native \
  pactl list short sinks

期待:

stream

source:

runuser -u nizika -- env \
  HOME=/var/lib/nizika \
  XDG_RUNTIME_DIR=/run/nizika \
  PULSE_SERVER=unix:/run/nizika/pulse/native \
  pactl list short sources

期待:

stream.monitor

headless 環境では PulseAudio が cookie や D-Bus 警告を表示する場合がある。

service が active で、pactl から streamstream.monitor が取得できていれば、この構成では致命的ではない。


13. Xvfb

作成:

/etc/systemd/system/xvfb.service

内容:

[Unit]
Description=Nizika virtual display

[Service]
Type=simple
User=nizika
Group=nizika

Environment=HOME=/var/lib/nizika

ExecStart=/usr/bin/Xvfb \
  :99 \
  -screen 0 480x360x16 \
  -nolisten tcp \
  -noreset \
  -dpi 96 \
  -extension RANDR \
  -extension RENDER \
  -extension DAMAGE \
  -extension COMPOSITE \
  -extension GLX

Restart=always
RestartSec=1

[Install]
WantedBy=multi-user.target

反映:

systemctl daemon-reload

systemctl enable \
  xvfb.service

systemctl start \
  xvfb.service

確認:

systemctl --no-pager --full status \
  xvfb.service

この設定では RANDR を無効化しているため:

Xlib: extension "RANDR" missing on display ":99".

という warning が出る場合がある。


14. broadcast environment

作成:

/etc/nizika-broadcast.env

内容:

NIZIKA_AI_MYSQL_USER=...
NIZIKA_AI_MYSQL_PASS=...

NIZIKA_NICO_MYSQL_USER=...
NIZIKA_NICO_MYSQL_PASS=...

NIZIKA_NICO_DIR=/opt/nizika-nico

BROADCAST_CODE=...

LD_LIBRARY_PATH=/usr/local/lib

権限:

chown root:root \
  /etc/nizika-broadcast.env

chmod 600 \
  /etc/nizika-broadcast.env

15. foreground smoke test

systemd 化する前に確認する。

cd /opt/nizika_broadcast

set -a
. /etc/nizika-broadcast.env

export HOME=/var/lib/nizika
export DISPLAY=:99
export SDL_AUDIODRIVER=pulse
export XDG_RUNTIME_DIR=/run/nizika
export PULSE_SERVER=unix:/run/nizika/pulse/native

set +a

timeout 20s \
  runuser -u nizika \
  --preserve-environment \
  -- \
  python3 main.py

rc=$?

echo "exit=$rc"

期待:

exit=124

124 は application crash ではなく、20 秒後に timeout が終了させたことを意味する。


16. nizika_broadcast.service

作成:

/etc/systemd/system/nizika_broadcast.service

内容:

[Unit]
Description=Deerjika Broadcasting System

After=network-online.target mysql.service pulseaudio-headless.service xvfb.service

Wants=network-online.target mysql.service

Requires=pulseaudio-headless.service xvfb.service

[Service]
Type=simple

User=nizika
Group=nizika

WorkingDirectory=/opt/nizika_broadcast

EnvironmentFile=/etc/nizika-broadcast.env

Environment=HOME=/var/lib/nizika
Environment=DISPLAY=:99
Environment=SDL_AUDIODRIVER=pulse
Environment=XDG_RUNTIME_DIR=/run/nizika
Environment=PULSE_SERVER=unix:/run/nizika/pulse/native

ExecStartPre=/bin/bash -lc 'for i in {1..50}; do pactl list short sources | grep -Fq stream.monitor && exit 0; sleep 0.2; done; echo "stream.monitor not found" >&2; exit 1'

ExecStartPre=/bin/bash -lc 'for i in {1..50}; do test -S /tmp/.X11-unix/X99 && exit 0; sleep 0.2; done; echo "Xvfb :99 not ready" >&2; exit 1'

ExecStart=/usr/bin/python3 \
  /opt/nizika_broadcast/main.py

Restart=always
RestartSec=2

[Install]
WantedBy=multi-user.target

反映:

systemctl daemon-reload

systemctl enable \
  nizika_broadcast.service

systemctl start \
  nizika_broadcast.service

確認:

systemctl --no-pager --full status \
  nizika_broadcast.service

17. YouTube stream key

stream key は source code や systemd unit へ直接記載しない。

作成:

/etc/nizika-stream.env

内容:

YOUTUBE_STREAM_KEY=...

権限:

chown root:root \
  /etc/nizika-stream.env

chmod 600 \
  /etc/nizika-stream.env

stream key をログや Wiki に記載しない。

漏洩した場合は古い key を無効化して新規発行する。


18. ffmpeg systemd service

作成:

/etc/systemd/system/nizika.service

内容:

[Unit]
Description=Nizika YouTube Stream

After=network-online.target pulseaudio-headless.service xvfb.service nizika_broadcast.service

Wants=network-online.target

Requires=pulseaudio-headless.service xvfb.service nizika_broadcast.service

[Service]
Type=simple

User=nizika
Group=nizika

WorkingDirectory=/opt/nizika_broadcast

EnvironmentFile=/etc/nizika-stream.env

Environment=HOME=/var/lib/nizika
Environment=DISPLAY=:99
Environment=XDG_RUNTIME_DIR=/run/nizika
Environment=PULSE_SERVER=unix:/run/nizika/pulse/native

ExecStartPre=/bin/bash -lc 'for i in {1..50}; do pactl list short sources | grep -Fq stream.monitor && exit 0; sleep 0.2; done; echo "stream.monitor not found" >&2; exit 1'

ExecStartPre=/bin/bash -lc 'for i in {1..50}; do test -S /tmp/.X11-unix/X99 && exit 0; sleep 0.2; done; echo "Xvfb :99 not ready" >&2; exit 1'

ExecStart=/usr/bin/ffmpeg \
  -nostdin \
  -f x11grab \
  -video_size 480x360 \
  -framerate 6 \
  -draw_mouse 0 \
  -i :99 \
  -f pulse \
  -i stream.monitor \
  -c:v libx264 \
  -preset ultrafast \
  -pix_fmt yuv420p \
  -b:v 100k \
  -maxrate 100k \
  -bufsize 200k \
  -g 12 \
  -r 6 \
  -c:a aac \
  -b:a 18k \
  -ar 11025 \
  -f flv \
  rtmps://a.rtmps.youtube.com:443/live2/${YOUTUBE_STREAM_KEY}

Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

反映:

systemctl daemon-reload

systemctl enable \
  nizika.service

systemctl start \
  nizika.service

確認:

systemctl --no-pager --full status \
  nizika.service

19. stream key と process list

ffmpeg の RTMPS URL は process argv に含まれる。

したがって:

systemctl status nizika.service

や:

ps

の出力に stream key が表示される場合がある。

外部へログを共有する際は必ず stream key を伏せる。


20. 全 service 確認

systemctl --no-pager --full status \
  pulseaudio-headless.service \
  xvfb.service \
  nizika_broadcast.service \
  nizika.service

すべて:

active (running)

であることを確認する。


21. 自動起動

確認:

systemctl is-enabled \
  pulseaudio-headless.service \
  xvfb.service \
  nizika_broadcast.service \
  nizika.service

すべて:

enabled

であれば、通常の reboot 後に systemd が自動起動する。


22. reboot test

最終的には一度再起動して確認する。

reboot

再ログイン後:

systemctl is-active \
  pulseaudio-headless.service \
  xvfb.service \
  nizika_broadcast.service \
  nizika.service

すべて:

active

が目標。


23. nullsink.service

旧環境で使用していた:

nullsink.service

は移行しない。

PulseAudio の:

/etc/nizika/pulse/default.pa

内で:

load-module module-null-sink sink_name=stream

を実行しているため、独立した null sink 用 service は不要。


24. 関連 repository

nizika_ai

AI 関連処理と nizika_ai DB を利用する。

environment variable:

NIZIKA_AI_MYSQL_USER
NIZIKA_AI_MYSQL_PASS

nizika_nico

共通処理や DB を利用する。

配置:

/opt/nizika-nico

environment variable:

NIZIKA_NICO_MYSQL_USER
NIZIKA_NICO_MYSQL_PASS
NIZIKA_NICO_DIR