---
sidebar_position: 99
title: ローカルサーバーでマイク・カメラを使う方法
description: HTTP + IPアドレスでブラウザのマイク・カメラが動かない問題の解決策
hide_table_of_contents: false
displayed_sidebar: null
image: ./banner.png
---

# ローカルサーバーでマイク・カメラを使う方法

## 問題

ローカルネットワーク上のサーバー（例: `http://192.168.1.100:7860`）にブラウザからアクセスすると、マイクやカメラが使えない。

```
NotAllowedError: Permission denied
```

## 原因

ブラウザの **セキュアコンテキスト** 制限。`getUserMedia()`（マイク・カメラ API）は以下の条件でのみ動作：

- `https://` — HTTPS接続
- `http://localhost` — ローカルホスト
- `http://127.0.0.1` — ループバック

**`http://192.168.x.x` は対象外。**

## 解決策

### 方法1: SSHトンネル（推奨）

最も簡単。リモートサーバーのポートを `localhost` にフォワード。

```bash
ssh -L 7860:localhost:7860 user@192.168.1.100
```

その後 `http://localhost:7860` でアクセス → マイク使用可能！

**複数ポートの場合：**

```bash
ssh -L 7860:localhost:7860 -L 8000:localhost:8000 user@192.168.1.100
```

### 方法2: Chromeフラグで許可

テスト用途に。特定のIPをセキュアコンテキストとして扱う。

1. Chromeで `chrome://flags` にアクセス
2. `Insecure origins treated as secure` を検索
3. 許可するURLを追加（例: `http://192.168.1.100:7860`）
4. Chrome再起動

:::warning
セキュリティが低下するため、開発・テスト用途に限定してください。
:::

### 方法3: 自己署名証明書でHTTPS化

チーム共有や本格運用向け。サーバー側でHTTPSを有効化。

#### Step 1: 証明書を生成

サーバー側で以下を実行：

```bash
openssl req -x509 -newkey rsa:4096 \
  -keyout key.pem \
  -out cert.pem \
  -days 365 \
  -nodes \
  -subj "/CN=192.168.1.100" \
  -addext "subjectAltName=IP:192.168.1.100"
```

| オプション | 説明 |
|-----------|------|
| `-keyout key.pem` | 秘密鍵ファイル（サーバーが使う、外部に漏らさない） |
| `-out cert.pem` | 証明書ファイル（クライアントに配布可能） |
| `-days 365` | 有効期限（1年） |
| `-nodes` | パスフレーズなし（サーバー自動起動用） |
| `-subj "/CN=..."` | Common Name（IPアドレスまたはホスト名） |
| `-addext "subjectAltName=..."` | SANs（最近のブラウザで必須） |

**生成されるファイル：**
```
key.pem   # 秘密鍵（絶対に公開しない）
cert.pem  # 証明書（クライアントに配布OK）
```

#### Step 2: サーバーで証明書を使う

**Gradio：**
```bash
python app.py --ssl-keyfile key.pem --ssl-certfile cert.pem
```

**FastAPI / Uvicorn：**
```bash
uvicorn main:app --host 0.0.0.0 --port 8000 \
  --ssl-keyfile key.pem --ssl-certfile cert.pem
```

**Python http.server（簡易）：**
```python
import ssl
import http.server

context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
context.load_cert_chain('cert.pem', 'key.pem')

server = http.server.HTTPServer(('0.0.0.0', 8000), http.server.SimpleHTTPRequestHandler)
server.socket = context.wrap_socket(server.socket, server_side=True)
server.serve_forever()
```

**Node.js / Express：**
```javascript
const https = require('https');
const fs = require('fs');
const app = require('./app');

https.createServer({
  key: fs.readFileSync('key.pem'),
  cert: fs.readFileSync('cert.pem')
}, app).listen(8000);
```

#### Step 3: ブラウザでアクセス

`https://192.168.1.100:8000` にアクセスすると警告が出る：

**Chrome:**
1. 「この接続ではプライバシーが保護されません」と表示
2. 「詳細設定」をクリック
3. 「192.168.1.100 にアクセスする（安全ではありません）」をクリック

**Firefox:**
1. 「警告: 潜在的なセキュリティリスクあり」と表示
2. 「詳細」→「危険性を承知で続行」

**Safari:**
1. 「この接続はプライベートではありません」と表示
2. 「詳細を表示」→「このWebサイトを閲覧」

#### Step 4: 証明書を信頼済みに登録（オプション）

毎回警告を出したくない場合、証明書をOSに登録。

**macOS:**
```bash
sudo security add-trusted-cert -d -r trustRoot \
  -k /Library/Keychains/System.keychain cert.pem
```

**Ubuntu/Debian:**
```bash
sudo cp cert.pem /usr/local/share/ca-certificates/myserver.crt
sudo update-ca-certificates
```

**Windows:**
1. `cert.pem` を `cert.crt` にリネーム
2. ダブルクリック → 「証明書のインストール」
3. 「ローカルマシン」→「信頼されたルート証明機関」に配置

:::tip
チームで共有する場合は `cert.pem` を配布し、各メンバーがOSに登録すると便利です。
:::

### 方法4: ngrok / Cloudflare Tunnel

外部サービス経由でHTTPS URL を取得。

```bash
ngrok http 7860
# → https://xxxx.ngrok.io が発行される
```

## 早見表

| 方法 | 難易度 | セキュリティ | 用途 |
|------|--------|------------|------|
| SSHトンネル | ★☆☆ | ◎ | 開発・日常利用 |
| Chromeフラグ | ★☆☆ | △ | 一時的なテスト |
| 自己署名証明書 | ★★☆ | ○ | チーム共有 |
| ngrok等 | ★★☆ | ◎ | 外部共有・デモ |

## 関連

- [DGX SparkでVibeVoice ASRを動かす](/tech/dgx-spark-vibevoice-asr/) — リアルタイム音声認識
