SoftEther VPN Server をDockerでビルド・運用するための一式です。
kh813/softether-automator の思想(ビルド自動化・バックアップ)を踏襲しつつ、
稼働自体もコンテナに寄せた構成にしています。
このプロジェクト(softether-docker/ 一式)は /opt/softether-docker/ に配置する想定です
(既存の softether-automator.sh が /opt/ 配下でビルドしてから /usr/vpnserver へ
make install する構成と揃えています)。
データ領域(vpn_server.config、ログ)は /opt/softether-docker/data に固定でハードコードしています。
プロジェクト自体をgit管理する場合は、.gitignore で data/ を除外済みなので、
誤って git clean 等で実行時データを消してしまう心配はありません。
migrate.sh 実行時、/opt/SoftEtherVPN_Stable
(softether-automator.sh が使うホストビルド用ソースディレクトリ)が既に存在する場合は、
警告を表示して停止します。新しいDocker運用ではこのディレクトリを使わないため、
古いホストビルドの残骸との混同を避ける目的です。表示された mv コマンドでリネームしてから再実行してください。
- SecureNAT (L3/NAT) 運用を想定しています。Local Bridge で物理LANへL2ブリッジしている場合、 この構成では動きません(host networkや追加のcapabilityが必要になり、別設計が必要です)。
- Docker Engine / Docker Compose v2 がホストにインストール済みであること
- ホストの
net.ipv4.ip_forward=1も別途有効化しておくことecho 'net.ipv4.ip_forward=1' | sudo tee /etc/sysctl.d/99-softether.conf sudo sysctl --system
softether-docker/
├── Dockerfile # マルチステージビルド(ビルド環境とランタイムを分離)
├── entrypoint.sh # 起動のたびにビルド成果物をデータ領域へ反映し、vpnserverを起動
├── docker-compose.yml # コンテナ定義(NET_ADMIN, /dev/net/tun, ポート, ボリューム)
├── .gitignore # data/ を除外(実行時データの誤削除防止)
├── scripts/
│ ├── lib.sh # 共通関数(履歴記録、build+up+verify処理)
│ ├── backup.sh # ホスト or データ領域のバックアップ
│ ├── install.sh # 新規セットアップ: 既存環境なしでゼロから起動
│ ├── migrate.sh # 初回移行: ホスト稼働 → Docker運用
│ ├── update.sh # 継続的なビルド/アップデート(失敗時ロールバック付き)
│ ├── rollback.sh # 任意の過去イメージタグへの手動ロールバック
│ ├── list-backups.sh # ロールバック候補(履歴/イメージ/バックアップ)の一覧表示
│ ├── prune.sh # 古いバックアップ/イメージの間引き
│ └── verify.sh # 動作検証(プロセス/API応答/ポート/ログ)
├── tools/
│ └── auth_log_aggregator.py # 認証ログ集計/Google Chat通知ツール(ホストで実行)
└── README.md
| 状況 | 実行するスクリプト |
|---|---|
| これから新規にセットアップする(既存のホスト稼働環境がない) | sudo ./scripts/install.sh |
softether-automator.sh 等で既にホスト上に /usr/vpnserver が稼働している |
sudo ./scripts/migrate.sh |
どちらも、/opt/SoftEtherVPN_Stable(旧ホストビルド用ソースディレクトリ)が
残っている場合は警告を表示して停止します。また install.sh は /usr/vpnserver が
既に存在する場合、migrate.sh は存在しない場合にも、それぞれ警告して停止します
(間違ったスクリプトを実行してしまうのを防ぐためです)。
cd softether-docker
sudo ./scripts/install.sh流れ:
- 事前チェック(
/opt/SoftEtherVPN_Stableと/usr/vpnserverの存在確認) - データ領域 (
/opt/softether-docker/data) の準備 - イメージビルド
- コンテナ起動・動作検証
初回は vpn_server.config が存在しないため、vpnserverが自動的にデフォルト設定を生成します。
起動後、以下でvpncmdに接続して管理者パスワード等の初期設定を行ってください:
docker exec -it softether-vpnserver /usr/vpnserver/vpncmd localhost /SERVERcd softether-docker
sudo ./scripts/migrate.sh流れ:
/usr/vpnserverを/var/backups/softether/にバックアップ- ホストの
vpnserversystemdサービスを停止 vpn_server.configとログをDockerのデータ領域 (/opt/softether-docker/data) にコピー- イメージビルド
- コンテナ起動
- 動作検証。失敗時は自動でコンテナを止め、ホストのsystemdサービスを再起動(ロールバック)
移行が成功したら、必要に応じて:
sudo systemctl disable vpnserverinstall.sh / migrate.sh で一度セットアップした後、日常的な操作は
基本的に docker compose コマンドだけで完結します。以下は softether-docker/ 直下で実行してください。
(イメージの再ビルドが絡むのは update.sh 実行時だけです)
サーバー再起動時の自動復旧について
docker-compose.yml に restart: unless-stopped を設定しているため、
OS再起動やDockerデーモンの再起動時、コンテナは自動的に起動し直します。
手動で docker compose up -d する必要があるのは、明示的に停止した後に再開する場合だけです。
ただしこれはDocker自体がOS起動時に自動起動する設定になっていることが前提です:
sudo systemctl enable dockerCPU・メモリ使用率の制限について
docker-compose.yml 内に deploy.resources.limits を定義しており、デフォルトで CPU使用コア: 2コア(コア0-1), CPU使用上限: 1.0コア分(合計100%、2コア各50%相当), メモリ: 1GB に制限しています。必要に応じて環境変数や .env で変更可能です:
CPUS=2.0 CPU_SET=0-3 MEMORY_LIMIT=2G docker compose up -d状態確認
docker compose ps
# もしくは
docker ps --filter name=softether-vpnserver起動 / 停止 / 再起動
docker compose start # 停止中のコンテナを再開
docker compose stop # コンテナは残したまま停止(configは無事)
docker compose restart # 再起動
docker compose up -d # コンテナが無ければ作成して起動、あれば何もしないdocker compose down はコンテナ自体を削除しますが、vpn_server.config やログは
ボリューム (/opt/softether-docker/data) に残るため、その後 docker compose up -d すれば
同じ設定で復元されます。日常的な停止には stop、設定変更後の作り直しには down → up -d、
という使い分けが目安です。
ログ確認
docker compose logs -f # リアルタイムで追う
docker compose logs --tail 100 # 直近100行vpncmdで接続する
docker exec -it softether-vpnserver /usr/vpnserver/vpncmd localhost /SERVERコンテナ内でシェルを開く(デバッグ用)
docker exec -it softether-vpnserver bashSecureNAT運用の場合、vpnserverプロセス自身がユーザー空間でNATするため、
コンテナがLAN側(物理ネットワークのセグメント)へ実際に到達できるかは、
docker execで直接確認しておくと安心です。verify.shには含めていない
(環境ごとにLAN側のIPアドレスが異なるため自動化しにくい)ので、移行直後に手動で実行してください。
直結セグメントへの疎通確認(例: eth1が192.168.5.0/24の場合)
docker exec softether-vpnserver ping -c 3 192.168.5.1ルーティングされた先のセグメントへの疎通確認 (例: 192.168.5.1経由の192.168.10.0/23、192.168.26.0/24など、実際に存在するホストのIPに置き換えてください)
docker exec softether-vpnserver ping -c 3 <LAN側の既知のホストIP>ICMPがLAN側でブロックされている環境向け(TCPレベルでの疎通確認)
docker exec softether-vpnserver nc -vz <LAN側の既知のホストIP> <ポート番号>
# 例: docker exec softether-vpnserver nc -vz 192.168.10.5 445いずれも失敗する場合は、Dockerのbridgeネットワーク自体の問題というより、 ホスト側のルーティングテーブルやファイアウォール(ufw/iptables)の設定を確認してください (コンテナからの疎通は最終的にホストのルーティング・NATに依存するため)。
認証成功/失敗を集計してコンソール表示、または Google Chat Webhook に通知するツールです。
コンテナの中ではなくホスト側で実行する前提です(データ領域がホストにbind mountされているため、
docker exec なしで直接ログファイルを読めます)。
初回利用前に、スクリプト冒頭の「設定」セクションを編集してください。
# Docker運用かOS直接インストールかで、使う行のコメントを切り替えてください(デフォルトはOS直接インストール運用)
VPN_SERVER_DIR = "/usr/vpnserver" # [パターンA] OSに直接インストールの場合 ← デフォルト
# VPN_SERVER_DIR = "/opt/softether-docker/data" # [パターンB] Docker運用の場合
VIRTUAL_HUB = "YourVirtualHubName" # ← 実際の仮想HUB名に変更する(--hubで実行時上書きも可)
GCHAT_WEBHOOK_URL = "your_webhook_url" # ← -w を使うなら実際のWebhook URLに変更する(--webhookで実行時上書きも可)使い方
# 当日分を集計してコンソールに表示
python3 tools/auth_log_aggregator.py
# 過去30日分を集計
python3 tools/auth_log_aggregator.py -d 30
# 過去7日分を集計し、Google ChatへWebhook通知(cron向け、進捗バー等は抑制)
python3 tools/auth_log_aggregator.py -d 7 -q -w
# 認証失敗の詳細(日時・ユーザー名等)も表示
python3 tools/auth_log_aggregator.py --details
# 仮想HUB名を実行時に指定(スクリプト内のデフォルト値を上書き。複数HUBを運用している場合など)
python3 tools/auth_log_aggregator.py --hub AnotherHub
# Webhook送信先URLを実行時に指定(スクリプト内のデフォルト値を上書き)
python3 tools/auth_log_aggregator.py -w --webhook https://chat.googleapis.com/v1/spaces/xxx/messages?key=...--webhook は値を省略すると(-w単体と同じく)スクリプト内のデフォルトURLを使います。
値を指定した場合のみ、その回の送信先を上書きします。--hubも同様に、省略時はスクリプト内の
デフォルトHUB名を使い、指定した場合のみその回だけ上書きします。
cronで毎朝9時に通知する例
ログファイルはコンテナ内のvpnserver(root権限で稼働)が作成するため、ホスト側でも root 所有になります。 そのため cron は root権限で実行する必要があります。
sudo crontab -e0 9 * * * /usr/bin/python3 /opt/softether-docker/tools/auth_log_aggregator.py -q -w
または /etc/cron.d/softether-auth-report に置く場合はuser列を明示してください:
0 9 * * * root /usr/bin/python3 /opt/softether-docker/tools/auth_log_aggregator.py -q -w
Webhook URLの扱いについて:スクリプト内に平文で書く形式のため、このsoftether-docker/一式をgit管理する場合は、
実際のWebhook URLを書き込んだ後は誤ってコミットしないよう注意してください。必要であれば
tools/auth_log_aggregator.py を .gitignore に加え、テンプレート用に別名でコミットする運用にしてもよいです。
cd softether-docker
./scripts/update.sh # デフォルト: SOFTETHER_REF=master
./scripts/update.sh v4.44-9807 # 特定バージョン/タグを指定する場合流れ:
- 現行データ領域をバックアップ
- 現行イメージをロールバック用にタグ付け退避
- 新しいソースでビルド
- コンテナ再作成(
vpn_server.configはボリューム上にあるため自動的に引き継がれる) - 動作検証。失敗時は自動的に旧イメージへロールバック
./scripts/verify.sh./scripts/list-backups.sh以下がまとめて表示されます:
- 現在稼働中のイメージタグ
- 更新履歴(
/var/lib/softether-docker/history.log): 日時・タグ・gitref・状態・紐づくデータバックアップ - ローカルに残っているDockerイメージ一覧
/var/backups/softether/配下のバックアップtarball一覧
update.sh は検証失敗時に直前世代へ自動でロールバックしますが、
「後になってから昔の世代に戻したい」場合は rollback.sh を使います。
./scripts/rollback.sh # 対話的に世代を選択
./scripts/rollback.sh 20260715_120000 # タグを直接指定流れ: 現行データ領域を安全のためバックアップ → コンテナ停止 → 指定タグで起動 → 動作検証 → 履歴記録。
対象イメージがローカルに残っていない場合(後述の prune.sh で消えた等)はエラーになります。
./scripts/prune.sh --dry-run # まず削除対象を確認
./scripts/prune.sh # 実削除(デフォルト: バックアップ10件 / イメージ5件を保持)
./scripts/prune.sh --keep-backups 20 --keep-images 8- 削除対象は
update.shが作るdata_*バックアップとsoftether-vpnserver:<timestamp>イメージのみです migrate.shが最初に作るhost_*バックアップ(移行前の全体バックアップ)は自動削除の対象外です。不要になったら手動で判断して削除してください- 現在稼働中のイメージタグと
rollbackタグは常に保護されます - 定期実行したい場合は
cronかsystemd timerに登録してください。例(毎週日曜3時):0 3 * * 0 root /path/to/softether-docker/scripts/prune.sh >> /var/log/softether-prune.log 2>&1
UNLOCK_FEATURES=true ./scripts/update.sh(自己責任での利用となります。元のスクリプトと同じ書き換えロジックをDockerfile内に組み込んでいます)
- Local Bridge(物理LANへのL2ブリッジ)には対応していません
vpn_server.config以外の細かいランタイム状態(証明書ファイルを別配置している場合など)を使っている場合は、migrate.shのコピー対象リストに追加してください