目次
- サーバー環境構築
- 1. service user
- 2. repository
- 3. OS package
- 4. Python package
- 5. Python 3.14 の注意
- 6. pip permission の注意
- 7. Python import test
- 8. AqKanji2Koe
- 9. AquesTalk2 Eva
- 10. PulseAudio
- 11. pulseaudio-headless.service
- 12. PulseAudio device 確認
- 13. Xvfb
- 14. broadcast environment
- 15. foreground smoke test
- 16. nizika_broadcast.service
- 17. YouTube stream key
- 18. ffmpeg systemd service
- 19. stream key と process list
- 20. 全 service 確認
- 21. 自動起動
- 22. reboot test
- 23. nullsink.service
- 24. 関連 repository
サーバー環境構築
概要
このページでは 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 から stream と stream.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