Chillarin Blog 構成紹介 - 6.ギミック:ライブ映像編 -
Google Nest Cam × go2rtc でチンチラのライブ映像をブログに埋め込む実装解説。カテゴリ別の表示制御・必要時だけ ON にする運用判断・X への配信予定自動投稿まで「ギミック」全体の組み立てをまとめる。
本章の内容
前回(5章)は「記事を書く → push → 自動反映」など、運用の自動化(CI/CD)をまとめました。 この章(6章)は、Chillarin Blog の “ギミック” の中でも一番インパクトがある チンチラのライブ映像 についてです。
やりたいことは次のとおりです。
- ブログの チンチラカテゴリ だけライブ枠を表示したい
- 配信は常時ONではなく、必要なときだけONにしたい(運用で疲れない)
- 音声はデフォルトOFF(事故防止)。必要なときだけONにしたい
- 配信ONにしたら Xへ配信予定時間を自動投稿したい(運用の見える化)
1. Google Nest Cam を採用した理由(リアル)
カメラは Google Nest Cam Outdoor(電源アダプター式 / 第2世代) を使っています。
(製品ページ:https://store.google.com/jp/product/nest_cam_outdoor_wired_2nd_gen?hl=ja)
1.1 Google Nest Cam ってそもそも何?
Google Nest Cam は、Google のスマートホーム基盤(Google Home)に統合される 見守り/防犯カメラです。 スマホの Google Home アプリから
- ライブ映像の視聴
- 動体/音などのイベント検知(通知)
- クリップ(イベント)や履歴の確認
といった「日常の見守り」ができるのが特徴です。
1.2 映像はどこに保存される?
Nest Cam の録画(イベント履歴など)は、基本的に カメラ → Wi-Fi → Google(Nest)のクラウドへアップロードされて管理されます。 (ローカルSDカードに常時録画して溜める、というタイプのカメラとは思想が違います)
※保存できる履歴の種類・期間は、利用しているプラン(サブスク)などで変わるため、ここでは「クラウド側で履歴として見返せる」という前提だけ押さえておけばOKです。
1.3 普段はどうやって見る?
普段の視聴は Google Home アプリが基本です。
- ライブ映像:Home アプリの「カメラ」一覧から対象カメラを開く
- 録画履歴(イベント):Home アプリの「アクティビティ」から確認する(機種や移行状況で画面導線は多少差が出ます)
PCから確認したい場合は、Google Home のWeb(ブラウザ)でライブ映像を見られるケースもあります。 今回はブログに組み込むためにひと工夫加えているので、その辺の話を後述します。
1.4 このブログで採用した理由(リアル)
採用理由は2つあります。
- チンチラ部屋は砂浴びで砂っぽい → 室内でも環境的には"屋外耐性がある機種"が安心
- きっかけはかなり現実的で、Pixel購入のポイントが余っていて期限が迫っていた → 「試しに買ってみた」から始まった
最初から配信システムを作る前提ではなく、日常の延長で “仕組み化” していった、というのがこの章の背景です。
2. 全体アーキテクチャ(何がどこにいる?)
ざっくりの流れはこうです。

- Nest Cam は Google(クラウド)側を経由してライブ視聴できる形になっている
- go2rtc が SDM API(OAuth)でライブ用ストリームセッションを生成し、払い出されたストリームを受信して再配信する
- クライアント端末がブログ(カテゴリページ)を閲覧し、ページ内のプレイヤー/iframe が go2rtc 側へアクセスする
- ブログ側は “埋め込みと制御” を担当する(status.json を見て表示を切り替える)
- 配信ON/OFFや音声、予定時間は、コントロールアプリで status.json を更新して操縦する
3. 実行基盤の整理:VM と LXC の違い/今回 LXC を選んだ理由
この構成は「全部VMに載せる」でも動きますが、今回は go2rtc を LXC に分離しています。
VM と LXC をざっくり比較(もう少し正確に)
VM(仮想マシン):ハイパーバイザー(例:Proxmox/KVM)の上で ゲストOSごと動かす方式
- CPU/RAM は「割り当て(上限)」を持つ:VMごとに vCPU 数やメモリ容量を設定し、その範囲で動く
- ただし CPU は物理コアに"専有"されるとは限らず、通常は スケジューリングで共有(必要なら CPU pinning で固定も可能)
- メモリは基本的に VMに割り当てた分が前提(バルーニングやKSM等で最適化はできるが、概念としては「VM単位で確保」)
- 分離が強い:カーネルも分かれるので、他の環境と干渉しにくい(セキュリティ境界も強め)
- オーバーヘッドがある:ゲストOS起動・ドライバ・更新など、運用対象が増える
- CPU/RAM は「割り当て(上限)」を持つ:VMごとに vCPU 数やメモリ容量を設定し、その範囲で動く
LXC(コンテナ / OSレベル仮想化):ホストの Linux カーネルを 共有し、namespace/cgroup で隔離する方式
- ゲストOSのカーネルは持たない:ホストのカーネル上でプロセスとして動く(ユーザ空間だけ分かれる)
- CPU/RAM は"共有しつつ制限する":
- CPU は cgroup で 割合(weight)や上限(quota) を設定でき、ホスト全体のCPUを前提に 取り合う
- メモリも cgroup で 上限設定できるが、基本はホストのメモリを 共有して使う(上限を超えると制限/killが起こり得る)
- 軽い・速い:起動が速く、ディスクも薄くしやすい(OS更新の運用負荷も小さめ)
- 分離はVMより弱め:同一カーネル共有なので、設計・権限設定(特に特権/非特権)を意識する必要がある
なぜ go2rtc を LXC にしたか(運用目線)
- go2rtc は “配信のエンジン” なので、落ちた時に切り分けしやすいように ブログVMから分離したかった
- LXC のほうが軽く、検証や再起動がラク
- Docker を LXC 上で動かすのも相性が良く、構成を独立させやすい
4. go2rtc とは何か(この構成での役割)
go2rtc は、ひと言でいうと 「映像ソースを受けて、配信プロトコルを変換・中継し、ブラウザ等のクライアントに配るための軽量なストリーミングゲートウェイ」 です。 (監視カメラの RTSP/HTTP/WebRTC など “入力の種類” がバラバラでも、視聴側は WebRTC / MSE / HLS など “扱いやすい形” で見られるように揃える、という立ち位置です)
「Nest Cam の映像を取り込み」の正確なニュアンス
ここは重要なので、言い方を正確にします。
- この構成で go2rtc がやっているのは、Nest Cam 本体にLAN内で直接ぶら下がって映像を吸い上げる…というより、
- Google Device Access(SDM API)経由で “ストリームセッション” を生成し、Google 側の仕組みを使って配信されるストリームを go2rtc が受信する、というイメージです。
Nest Cam は基本的に “Google のサービスに紐づいたカメラ” なので、 (ローカルに RTSP を生やして直接引けるカメラとは違い)Google 側の認証・権限・セッション生成(OAuth/SDM API) を通す前提になります。
結果として、
- カメラ <-> Google(認証・制御・配信の土台)
- go2rtc は SDM API を使ってストリームの払い出しを受ける側(受信クライアント)
- 受け取ったストリームを ブログ/ブラウザが再生しやすい形で再配信する側(配信サーバ)
という “橋渡し” になります。
このブログ構成での go2rtc の役割(何を解決しているか)
この章の構成だと、go2rtc は主に次を担います。
- 配信の入口を1つにまとめる Nest Cam 由来のストリーム(Google/SDM)を、ブログから扱いやすい “いつもの入口(go2rtc)” に集約する
- ブラウザで見やすい形に揃える 視聴側が WebRTC/MSE で再生できるように、プロトコルや配信の都合を吸収する
- 運用に強い設計を作る土台
- 必要に応じて ffmpeg を噛ませて「無音」「音あり」を作り分ける
- 複数クライアントからの視聴(ブログ閲覧者)を受け止める"中継点"になる
- Cloudflare Tunnel 側は「go2rtc が提供するパスだけ」を通せばよい、という形に寄せられる
この構成での “配信ハブ” としてのまとめ
この構成では go2rtc は、
- SDM API 経由で Nest Cam のストリームセッションを受ける(受信側)
- 必要なら ffmpeg で加工して、無音/音ありを作り分ける(整形/分岐)
- ブラウザで再生しやすい形(WebRTC/MSE)で配る(配信側)
という意味で「配信ハブ」になっています。
5. Google 側の準備(Nest Cam を API で扱うための設定)
5章/6章に関しては、実際の設定方法(画面スクショ付き)は別記事でまとめようと思っております。 ここでは「何をやるか」と「詰まりやすい前提」だけ押さえます。
5.1 やること(全体像)
- Google Cloud 側で Device Access / SDM API を使う準備
- OAuth クライアント作成(Client ID/Secret)
- refresh_token を用意
- go2rtc の
streams:にnest:?形式で認証情報を渡す
5.2 ハマりやすい前提(最初に知っておくと楽)
go2rtc の Nest 連携は、「nest 用の別設定ブロック」を書く方式ではなく、
streams: に nest:? を定義し、視聴要求が来た時に初めて動く、という挙動になりがちです。
そのため、
- 起動直後に
[nest]ログが出ないからといって、必ずしも壊れているとは限らない - 逆に、再生時に
wrong queryが出るなら “nest ソースとして解釈できていない” 可能性が高い
という前提を持っておくと、切り分けが一気に早くなります。
6. go2rtc 側の設定(Docker + go2rtc.yaml)
ここは “最終的にどういう思想で設定しているか” を書きます。
streams:に Nest のソース(nest:?)を定義- そこから派生で、無音/音ありストリームを作る
- ブログからは “用途に応じて再生先を切り替える”
この章のポイントは「配信を作る」ではなく、次の 8章のために “無音と音あり” の2系統に分けられる土台を作ることです。
この設定ファイルの全量は 有料コンテンツ: 自宅サーバ構築シリーズ に含まれています。
6.1 実ファイル配置(/opt/nest-stream)
go2rtc は **専用ホスト(chilla-media-sv01)**上の /opt/nest-stream で管理しています。
このディレクトリに Docker Compose 定義と go2rtc 設定ファイルをまとめて置く構成です。
フォルダ構成(実機)
/opt/nest-stream/
├── docker-compose.yml # go2rtc コンテナ定義(起動・再起動方針)
├── go2rtc.yaml # go2rtc 本体設定(streams 定義)
└── go2rtc.yaml.old # 過去の設定バックアップ(任意)補足:このディレクトリは root 所有になっているため、編集時は
sudoが必要です。
6.2 docker-compose.yml の役割(Dockerで何が動いているか)
docker-compose.yml は **go2rtc コンテナ(alexxit/go2rtc)**を起動するための定義です。
この構成のポイント
image: alexxit/go2rtc:latest- go2rtc本体のDockerイメージ(最新タグ追従)container_name: master- コンテナ名はmaster(ログ確認などで使う)network_mode: host- WebRTC系の都合で host mode を採用(ポートマッピングの沼を避ける)- 設定の正本は
/opt/nest-stream/go2rtc.yamlを volume マウントで渡す restart: unless-stopped- OS再起動後も復帰しやすい
メモ:docker compose v2 では
version: "3.8"は obsolete 扱いになり警告が出るため、 気になる場合はversion:行を削除してOKです(動作には影響しません)。
docker-compose.yml の全量は 有料コンテンツ: 自宅サーバ構築シリーズ に含まれています。
6.3 go2rtc.yaml の役割(streams 定義が最重要)
go2rtc のキモは streams: の定義です。
ここで **入力(Nest Cam)**と、**用途別の出力(音なし/音あり)**を作っています。
設計意図
nest_srcを 元ソースとして固定nest_silentは **普段使い(音なし)**で安定運用nest_soundは **必要時のみ(音あり)**で利用
注意:
nest:?のURLには&が含まれるため、YAMLでは 必ずダブルクォートで囲むのが安全です。
go2rtc.yaml の全量(streams定義・認証情報の渡し方・ffmpeg変換パラメータを含む)は 有料コンテンツ: 自宅サーバ構築シリーズ に含まれています。
6.4 起動・状態確認・ログ確認(権限エラー回避含む)
起動(初回 / 再起動)
cd /opt/nest-stream
sudo docker compose up -d状態確認
sudo docker compose ps
sudo docker ps --format 'table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}'ログ確認(詰まったらまずここ)
sudo docker logs --tail 200 master補足:
permission denied while trying to connect to the Docker daemon socket ...が出る場合、dockerコマンドをsudo付きで実行してください。 (恒久対策として docker グループ付与もありますが、運用方針により選択)
6.5 LISTEN確認(1984が必須)
go2rtc の WebUI は 1984/TCP で待ち受けます。
ss -lntp | grep 1984(期待例)
LISTEN 0 4096 *:1984 *:*6.6 ブラウザ確認(go2rtc WebUI / 再生チェック)
WebUI:
http://<go2rtc-host>:1984/音声なし(推奨):
http://<go2rtc-host>:1984/stream.html?src=nest_silent音声あり(任意):
http://<go2rtc-host>:1984/stream.html?src=nest_soundここまで確認できれば、go2rtc 側は「起動・設定・Nest連携」が完了です。
7. Cloudflare 側の公開ルート設計(“思ったより通すものが多い” 問題)
ライブ映像は “ブログに埋め込む” ので、最終的には閲覧者のブラウザが
- go2rtc の
stream.html - JavaScript(
video-rtc.js/video-stream.jsなど) - go2rtc の
apiやstatic - status.json
といった複数のパスへアクセスします。
つまり、Cloudflare Tunnel で path-based に振り分けている場合、 「必要なものを全部、公開アプリケーション(公開ルート)に追加しておく」 必要があります。
7.1 なぜ video-rtc.js だけでは動かなかったのか
最初は「video-rtc.js を通せば動く」となりがちです。
でも実際は、stream.html がさらに api や static を参照し、追加で video-stream.js を読み…と依存が連鎖します。
結果として、何か1つでも欠けると
- 画面は出るがずっと
loading - 再生処理は進まず、ユーザ視点では “止まっている”
という状態になりやすいです。
7.2 不足パスの特定は DevTools が最短ルート
最終的には、ブラウザの開発ツール(DevTools)を見て足していくのが一番早いです。
- 対象ページを開く(チンチラカテゴリ、または stream.html)
- DevTools → Console / Network を開く
- 失敗しているリクエスト(赤い行)を確認
- そのパスを Cloudflare Tunnel の「公開アプリケーション ルート」に追加
- リロードして再チェック(これを繰り返す)
7.3 ルート追加のコツ(順序)
公開ルートは、設定の順番や * の置き方によって “意図しないマッチ” が起きます。
基本は、
stream.html/api/static/video-*.js/status.jsonなど 具体的なパスを上に- 最後に
*(ブログ本体)
という並びにしておくと事故が減ります。
7.4 最終的に通したもの(例)
あなたの構成では、最終的に下記のような複数パスが必要になりました。
stream.html→ go2rtcapi→ go2rtcstatic→ go2rtcvideo-stream.js→ go2rtcvideo-rtc.js→ go2rtcstatus.json→ コントロールアプリ*(その他)→ ブログ本体
「最初から全部を予想する」のは難しいので、 DevTools で “実際にブラウザが何を取りに行っているか” を見て埋めるのが正解です。
Cloudflare Tunnel の振り分けルール全量(パス・サービスURL・順序の完全な対応表)は 有料コンテンツ: 自宅サーバ構築シリーズ に含まれています。
8. 2系統ストリーム設計(運用に強い"無音"と"音あり")
ライブ映像は「技術的に見える」だけでなく、「運用で回る」ことが重要です。 そこで、この構成は 無音と音ありを分ける 方針にしています。
- 常時表示用:無音(自動再生・負荷・事故防止)
- イベント用:音あり(必要な時だけ)
常時表示を “無音” に寄せる理由
- ブラウザの自動再生ポリシーに引っかかりにくい
- 音声が出る事故を避けられる(プライバシー/生活音)
- 常時ONでも心理的負担が少ない
イベント時だけ音声ONにする理由
- 音声は情報量が大きいが、そのぶん事故りやすい
- “必要なときだけ” 明示的にONすることで運用を楽にする
ffmpeg 変換の意図(軽量化/互換性)
入力ソースや視聴環境の相性で、映像/音声のコーデックが噛み合わないと再生できません。 ffmpeg を挟むのは、
- ブラウザ互換性を上げる(よくある形式に寄せる)
- 音声有無を明示的に分ける
- 不要な負荷を減らす
ための “運用最適化” です。
9. ブログ側の埋め込み(チンチラカテゴリだけライブ枠を出す)
やりたいことは “チンチラのページだけライブ枠を出す” です。
sidebar.html の条件分岐(カテゴリ判定の方針)
- Hugo のテンプレートでカテゴリ/セクションを判定
- 一致したときだけライブ枠のHTML(iframe等)を出す
iframe / プレイヤーの出し分け(見せ方のUX)
- 通常は無音のライブ枠(常時表示の邪魔にならない)
audio=trueのときだけ音ありプレイヤーに切り替える (※この切替は 10章の status.json とセットで完成します)
10. status.json で制御する設計(ON/OFF・音声・予定表示)
静的ブログでも “動的な制御” をしたいので、ブログ側は status.json を読みにいきます。
10.1 status.json のスキーマ
代表的に以下のフィールドを持ちます。
active:配信ON/OFFaudio:音声ON/OFFshow_schedule:配信予定の表示ON/OFFstart/end:配信予定時間(例:09:00〜18:00)
status.json の完全なスキーマ定義(フィールド一覧・型・デフォルト値・バリデーションルール)は 有料コンテンツ: 自宅サーバ構築シリーズ に含まれています。
10.2 ポーリング、キャッシュ無効化、CORS の考え方
ブラウザは status.json を定期的に取りに行きます。 この時に安定化の鍵になるのが次の2つです。
- CORS:別パス/別サービスから取る場合、CORS を許可する
- キャッシュ:status.json が更新されても、古いJSONを掴むと表示が変わらない
→
Cache-Control: no-cache, no-store, must-revalidateのようなヘッダを付ける
10.3 “運用で壊れない"ための判断ロジック
status.json を “真実の状態” として持つことで、
- 予定時間外はライブ枠を出さない
- active=false の時はプレイヤーを出さない
- audio=false をデフォルトにして事故を防ぐ
といった運用ルールを、ブログ側で一貫して適用できます。
11. 配信コントロールアプリ(/opt/nest-control)
配信のON/OFFや音声切替を “スマホで” 操作したいので、簡単なWeb UIを用意します。 このアプリは status.json を更新する司令塔です。
11.1 できること(ON/OFF、音声切替、予定時間、予定表示)
UI上で以下を操作できます。
active(配信ON/OFF)audio(音声ON/OFF)show_schedule(予定表示)start/end(配信予定時刻)
11.2 画面UIの意図(スマホ前提の操作性)
スマホから操作する前提なので、
- 迷わないトグル設計(ON/OFF、Audio、Schedule)
- 予定時刻は “入力が早い” 形式(HH:MM)
- 今の状態がすぐ分かる(現在の status.json を表示)
という “運用UI” を狙っています。
11.3 二重実行・二重反映のガード(設計思想)
運用で怖いのは “連打” や “反映遅延” です。 このアプリは、少なくとも次の思想で事故を減らします。
- 更新後は status.json を即反映し、ブログ側はポーリングで追従する
- ON/OFFや音声は status.json を真実にして、ブログ側で一貫して読む
11.4 配信ONで Xへ自動投稿(配信予定時間を投稿)
このアプリは、配信を OFF→ON に切り替えた瞬間だけ、Xに投稿します。
- OFF→ON の “一度だけ” にすることで、二重投稿を防ぎやすい
- 投稿内容は「配信開始予定(start〜end)」を含む短文にする
- 投稿は Make などの外部連携ではなく、アプリから直接 X API へ送信する
二重投稿防止(実装の考え方)
二重投稿は “運用上の事故” なので、状態ファイル(例:tweet_state.json)でガードします。
配信をOFFに戻した時にリセットする設計にしておくと、次回ON時にまた投稿できます。
12. トラブルシュート集(ハマりどころ総まとめ)
ここが一番 “実戦的” な話です。 今回のハマりどころは大きく2系統でした。
- A) go2rtc / Nest 連携(認証・クエリ・producerが立たない)
- B) Cloudflare 側(必要なパスが通っておらず、ブラウザが必要な資材を取れない)
12.1 「loading から動かない」
多くの場合、
- プレイヤーUIは表示されるが、ソースが取得できていない
- もしくは、依存リソース(JS/API)が読み込めていない
という状態です。
最初に見る場所は2つです。
- DevTools → Network(404/403/502 が出ていないか)
- go2rtc のログ(producerが立っているか、Nest側のエラーが出ていないか)
12.2 wrong query / 401 Unauthorized
wrong query:nest:?のクエリ形式が壊れている、もしくは “Nestソースとして解釈されていない” サイン401 Unauthorized:Google API へ到達しているが認証が通っていないサイン
この2つが出たら、まず Google 側設定(Client/Secret/Token)と、go2rtc の streams: 記述を疑います。
12.3 token 文字列と URL エンコード
refresh_token などは + や / を含む場合があり、クエリ文字列として扱うと解釈が壊れることがあります。
怪しい場合は URL エンコードを検討します(必須ではないが保険)。
12.4 ログの見方(どこを見れば切り分けできるか)
- ブラウザ:DevTools(Console/Network)
- go2rtc:コンテナログ(入力取得、変換、WebRTCハンドシェイク)
- Cloudflare:公開ルートの不足、順序ミス
「どこで止まっているか」を3点で分ければ、だいたい詰まりません。
13. 運用Tips(チンチラ部屋ならでは)
砂対策・設置位置・継続運用の工夫
チンチラは砂浴びをするので、部屋は想像以上に砂っぽくなります。
- カメラは “砂の直撃” を避ける位置に置く
- 掃除やメンテ前提で、配線や固定方法を考える
- Outdoor機種を選ぶと心理的に安心(壊れにくい前提で運用できる)
音声をデフォルトOFFにする理由(プライバシー/事故防止)
音声は事故りやすいので、基本OFFにします。
- 生活音や会話が入るとリスクが高い
- 常時ONだと心理的負担が大きい
- 必要な時だけONにすれば運用が続く
公開範囲とセキュリティ(Tunnel、アクセス制御)
「ライブ配信」は公開範囲が広いほど事故りやすいです。
- Tunnelの公開ルートは最小限にする
- ルート順序(具体パス→最後に
*)を守る - 必要なら Access(認証)も検討する
まとめ/次章予告(レイアウト・コメント編へ)
この章の結論は「ライブ映像を出す」ではなく、運用で回るように設計するです。
- go2rtc は配信のエンジン。LXC 分離で切り分けが楽になる
- status.json を “真実の状態” にして、静的ブログでも制御できる
- Cloudflare は 通すべきパスが想像より多い。DevTools で見て足すのが最短ルート
- 配信ON時は X に予定時間を自動投稿し、運用を楽にする
次回(7章)は、レイアウト・背景・コメント(Remark42)など、見た目と体験を整える話に入ります。
自宅サーバ運用の全体像は 自宅サーバ運用の完全ガイド — Proxmox + Cloudflare Tunnel + Docker で個人ブログを公開し続ける にまとめています。Proxmox クラスタ・公開経路・Docker 本番化・障害対応までを 1 ページで通読できる Pillar ガイドです。
コメント