DockerでNordVPNプロキシサーバーを構築する方法

# DockerでNordVPNプロキシサーバーを構築する方法

## はじめに
過去にnordvpn proxy dockerについて解説をした。

https://qiita.com/holndal/items/16e939bcda0479f7daf9

ただ、このDockerHubやGithubを見たところ4年commitがなく、メンテされていなさそうなので突然使えなくなった時凄い困ることが判明しました。

なので
[Docker hub](https://hub.docker.com/r/jeroenslot/nordvpn-proxy)
github
[Joentje](https://github.com/Joentje) / [nordvpn-proxy](https://github.com/Joentje/nordvpn-proxy)
のレポジトリについて細かく解説・分析しました。


## 主な機能

- **自動サーバー選択**: NordVPN APIを使用して最適なサーバーに自動接続
- **負荷分散**: サーバー負荷が高い場合に自動的に再接続
- **ランダムサーバー選択**: 上位N個の推奨サーバーからランダムに選択可能
- **ヘルスチェック機能**: 接続の安全性を定期的に確認
- **Privoxyプロキシ**: ブラウザなど外部アプリケーションからの利用が可能
- **コンテナ間通信**: 他のDockerコンテナをVPN経由で通信させることが可能
- **自動更新**: OpenVPN設定ファイルを毎日自動更新

## アーキテクチャ概要

### ディレクトリ構造

```
nordvpn-proxy/
├── Dockerfile          # Alpineベースのコンテナイメージ定義
├── docker-compose.yml  # Docker Compose設定ファイル
├── README.md          # プロジェクトドキュメント
└── app/
    ├── date.sh        # 日付フォーマット用ヘルパー関数
    ├── crond/         # Cronジョブ管理
    │   └── run        # Cronデーモン起動スクリプト
    ├── ovpn/          # OpenVPN関連
    │   ├── get-ovpn-files.sh      # OpenVPN設定ファイルダウンロード
    │   ├── get-status-server.sh   # サーバー負荷チェック
    │   ├── run                    # OpenVPN起動スクリプト
    │   └── servers_recommendations.sh  # 最適サーバー選択
    └── privoxy/       # Privoxyプロキシ
        ├── config     # Privoxy設定ファイル
        └── run        # Privoxy起動スクリプト
```

## 動作の仕組み

### 1. コンテナの起動プロセス

1. **Alpineベースイメージの使用**
   - 軽量なAlpine Linux 3.10.1をベースに構築
   - 必要なパッケージ（OpenVPN、Privoxy、runit、jq等）をインストール

2. **runitによるプロセス管理**
   - `/app`ディレクトリ内の各サービスをrunitで管理
   - 各サービスは`run`スクリプトで起動

### 2. OpenVPN設定ファイルの管理

`get-ovpn-files.sh`スクリプトの動作：

```bash
# NordVPNから最新のOpenVPN設定ファイルをダウンロード
curl -s -o ${OVPN_CONFIG_DIR}/ovpn.zip ${OVPN_FILES}

# ファイルを解凍
unzip -q ${OVPN_CONFIG_DIR}/ovpn.zip -d ${OVPN_CONFIG_DIR}
```

- 設定ファイルは`REFRESH_TIME`（デフォルト120分）経過後に再ダウンロード
- 毎日自動的に最新の設定ファイルを取得（Cronジョブ）

### 3. 最適なVPNサーバーの選択

`servers_recommendations.sh`の処理フロー：

1. **サーバー未指定の場合**
   - NordVPN APIから推奨サーバーリストを取得
   - 国コードが指定されている場合は、その国のサーバーに限定
   - `RANDOM_TOP`が設定されている場合、上位N個からランダム選択

2. **APIエンドポイント**
   ```
   https://api.nordvpn.com/v1/servers/recommendations
   ```

3. **フィルタリング条件**
   - OpenVPNプロトコル（TCP/UDP）対応サーバー
   - 指定国のサーバー（COUNTRY環境変数使用時）

### 4. VPN接続の確立

`run`スクリプトでOpenVPN接続を開始：

1. **TUNデバイスの作成**
   ```bash
   mknod /dev/net/tun c 10 200
   ```

2. **認証情報の設定**
   ```bash
   echo "$USERNAME" > auth.conf
   echo "$PASSWORD" >> auth.conf
   ```

3. **OpenVPN起動**
   ```bash
   openvpn --config ${SERVER}.${PROTOCOL}.ovpn --auth-user-pass auth.conf
   ```

### 5. Privoxyプロキシサーバー

- ポート8118でHTTPプロキシを提供
- VPN接続確立後10秒待機してから起動
- ローカルネットワークへのルーティング設定

### 6. ヘルスチェックとメンテナンス

1. **ヘルスチェック**（1分間隔）
   ```bash
   curl -x localhost:8118 https://api.nordvpn.com/vpn/check/full
   ```
   - VPN接続が「Protected」状態であることを確認

2. **負荷チェック**（Cronジョブ）
   - サーバー負荷が設定値（デフォルト75%）を超えた場合、自動的に再接続
   - `get-status-server.sh`が定期的に実行

## 環境変数の詳細

| 変数名 | 必須 | デフォルト値 | 説明 |
|--------|------|--------------|------|
| USERNAME | ✓ | - | NordVPNアカウントのユーザー名 |
| PASSWORD | ✓ | - | NordVPNアカウントのパスワード |
| LOCAL_NETWORK | ✓ | - | ローカルネットワークのCIDR（例: 192.168.1.0/24） |
| CRON | - | */15 * * * * | サーバー負荷チェックの頻度 |
| LOAD | - | 75 | サーバー負荷の閾値（%） |
| RANDOM_TOP | - | - | ランダム選択するサーバー数 |
| COUNTRY | - | - | 接続する国の2文字コード（例: JP） |
| PROTOCOL | - | tcp | 使用するプロトコル（tcp/udp） |
| SERVER | - | - | 特定のサーバー名（例: jp123.nordvpn.com） |
| REFRESH_TIME | - | 120 | 設定ファイル更新間隔（分） |

## 使用方法

### 1. 基本的な起動方法

```bash
docker run -d \
  --cap-add=NET_ADMIN \
  --name=vpn \
  --dns=103.86.96.100 \
  --dns=103.86.99.100 \
  --restart=always \
  -e "USERNAME=your_nordvpn_username" \
  -e "PASSWORD=your_nordvpn_password" \
  -e "LOCAL_NETWORK=192.168.1.0/24" \
  -v /etc/localtime:/etc/localtime:ro \
  -v ovpn-data:/app/ovpn/config \
  -p 8118:8118 \
  jeroenslot/nordvpn-proxy:latest
```

### 2. Docker Composeを使用する場合

```yaml
version: '3'
services:
  vpn:
    image: jeroenslot/nordvpn-proxy:latest
    cap_add:
      - NET_ADMIN
    devices:
      - /dev/net/tun
    dns:
      - 103.86.96.100
      - 103.86.99.100
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - ovpn-data:/app/ovpn/config
    environment:
      - USERNAME=your_nordvpn_username
      - PASSWORD=your_nordvpn_password
      - LOCAL_NETWORK=192.168.1.0/24
    ports:
      - 8118:8118
    restart: always

volumes:
  ovpn-data:
```

### 3. 他のコンテナからVPNを使用

```bash
docker run -d \
  --network="container:vpn" \
  your-image-name
```

### 4. ブラウザでプロキシを使用

ブラウザのプロキシ設定で以下を指定：
- プロキシサーバー: `Dockerホストのアドレス`
- ポート: `8118`

Chrome拡張機能「Proxy SwitchyOmega」の使用を推奨

## 高度な設定例

### 日本のサーバーに接続

```bash
docker run -d \
  # ... 他の設定 ...
  -e "COUNTRY=JP" \
  jeroenslot/nordvpn-proxy:latest
```

### ランダムサーバー選択を有効化

```bash
docker run -d \
  # ... 他の設定 ...
  -e "LOAD=0" \
  -e "RANDOM_TOP=100" \
  jeroenslot/nordvpn-proxy:latest
```

### 特定のサーバーを指定

```bash
docker run -d \
  # ... 他の設定 ...
  -e "SERVER=jp123.nordvpn.com" \
  jeroenslot/nordvpn-proxy:latest
```

## セキュリティ考慮事項

1. **認証情報の管理**
   - USERNAME/PASSWORDは環境変数で管理
   - Docker Secretsの使用を推奨

2. **ネットワーク権限**
   - NET_ADMIN capabilityが必要
   - TUNデバイスへのアクセス権限

3. **DNS設定**
   - NordVPNのDNSサーバーを使用（103.86.96.100、103.86.99.100）

## トラブルシューティング

### VPN接続が確立できない場合

1. 認証情報を確認
2. ログを確認: `docker logs vpn`
3. OpenVPN設定ファイルの更新を強制実行

### プロキシに接続できない場合

1. コンテナのポートマッピングを確認
2. LOCAL_NETWORKの設定を確認
3. ファイアウォール設定を確認

### パフォーマンスの問題

1. LOAD値を調整して頻繁な再接続を防ぐ
2. 特定のサーバーを指定して安定性を向上
3. プロトコルをUDPに変更してみる

## まとめ

理解したので万が一困っても直せますね
ヤッタ！


# 宣伝(招待リンク)

[お友達紹介リンク](https://refer-nordvpn.com/ClziUzUtdba) を使用した登録は下記の特典が付くので、もし検討している方はご一考ください。

```
- 1年または2年プランを選ぶと3か月分の無料期間
- 1か月プランを選ぶと1か月分の無料期間
がもらえます。
```

書いていて思いましたが、結構紹介特典がしょぼいので[ハピタス](https://m.hapitas.jp/item/detail/itemid/77465?i=24116723&route=pcText&apn=itemsharelink)経由でダウンロードしてポイント貰った方がお得かもしれません。