TECH · HOMELAB · HOMELAB

Chillarin Blog 構成紹介 - 6.ギミック:ライブ映像編 -

Google Nest Cam × go2rtc でチンチラのライブ映像をブログに埋め込む実装解説。カテゴリ別の表示制御・必要時だけ ON にする運用判断・X への配信予定自動投稿まで「ギミック」全体の組み立てをまとめる。

tech 2026-01-11 69 min read by ちらりん
cover · 1024×1024

本章の内容

前回(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. 全体アーキテクチャ(何がどこにいる?)

ざっくりの流れはこうです。

flowchart LR Cam["Google Nest Cam"] --> Google["Google (Device Access / SDM API)"] Google --> Go["go2rtc (LXC上 Docker)"] Go --> Blog["Hugo Blog (VM)"] Blog --> Viewer["Viewer Browser"] Ctrl["配信コントロールApp (/opt/nest-control)"] --> Status["status.json"] Status --> Blog
Live Stream機能概要(GIF)
Live Stream機能概要(GIF)
  • 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起動・ドライバ・更新など、運用対象が増える
  • 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 設定ファイルをまとめて置く構成です。

フォルダ構成(実機)

snippet
/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 起動・状態確認・ログ確認(権限エラー回避含む)

起動(初回 / 再起動)

bash
cd /opt/nest-stream
sudo docker compose up -d

状態確認

bash
sudo docker compose ps
sudo docker ps --format 'table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}'

ログ確認(詰まったらまずここ)

bash
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 で待ち受けます。

bash
ss -lntp | grep 1984

(期待例)

snippet
LISTEN 0 4096 *:1984 *:*

6.6 ブラウザ確認(go2rtc WebUI / 再生チェック)

WebUI:

snippet
http://<go2rtc-host>:1984/

音声なし(推奨):

snippet
http://<go2rtc-host>:1984/stream.html?src=nest_silent

音声あり(任意):

snippet
http://<go2rtc-host>:1984/stream.html?src=nest_sound

ここまで確認できれば、go2rtc 側は「起動・設定・Nest連携」が完了です。


7. Cloudflare 側の公開ルート設計(“思ったより通すものが多い” 問題)

ライブ映像は “ブログに埋め込む” ので、最終的には閲覧者のブラウザが

  • go2rtc の stream.html
  • JavaScript(video-rtc.js / video-stream.js など)
  • go2rtc の apistatic
  • status.json

といった複数のパスへアクセスします。

つまり、Cloudflare Tunnel で path-based に振り分けている場合、 「必要なものを全部、公開アプリケーション(公開ルート)に追加しておく」 必要があります。

7.1 なぜ video-rtc.js だけでは動かなかったのか

最初は「video-rtc.js を通せば動く」となりがちです。 でも実際は、stream.html がさらに apistatic を参照し、追加で video-stream.js を読み…と依存が連鎖します。

結果として、何か1つでも欠けると

  • 画面は出るがずっと loading
  • 再生処理は進まず、ユーザ視点では “止まっている”

という状態になりやすいです。

7.2 不足パスの特定は DevTools が最短ルート

最終的には、ブラウザの開発ツール(DevTools)を見て足していくのが一番早いです。

  1. 対象ページを開く(チンチラカテゴリ、または stream.html)
  2. DevTools → Console / Network を開く
  3. 失敗しているリクエスト(赤い行)を確認
  4. そのパスを Cloudflare Tunnel の「公開アプリケーション ルート」に追加
  5. リロードして再チェック(これを繰り返す)

7.3 ルート追加のコツ(順序)

公開ルートは、設定の順番や * の置き方によって “意図しないマッチ” が起きます。 基本は、

  • stream.html / api / static / video-*.js / status.json など 具体的なパスを上に
  • 最後に *(ブログ本体)

という並びにしておくと事故が減ります。

7.4 最終的に通したもの(例)

あなたの構成では、最終的に下記のような複数パスが必要になりました。

  • stream.html → go2rtc
  • api → go2rtc
  • static → go2rtc
  • video-stream.js → go2rtc
  • video-rtc.js → go2rtc
  • status.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/OFF
  • audio:音声ON/OFF
  • show_schedule:配信予定の表示ON/OFF
  • start / end:配信予定時間(例:09:0018: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 querynest:? のクエリ形式が壊れている、もしくは “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 ガイドです。

· · ·

コメント