Windows Server 2016 / 2019 でだけ FTP クライアントが「接続はできるのに転送時にタイムアウトする」「同じ C# プログラムなのにサーバーごとに結果が違う」といった現象は、IIS の設定とネットワーク機器の組み合わせでよく起こります。本記事では、Server A では成功するのに Server B では失敗するケースを題材に、原因の切り分けと具体的な対処方法を、実運用を意識した手順で整理します。
Windows Server 2016/2019 で FTP クライアント接続がタイムアウトする典型的な状況
まず、本記事の前提となる代表的なケースを整理します。
- 同じ C# 製 FTP 転送プログラムを使用
- Server A では正常にファイルアップロード/ダウンロードが完了
- Server B では データチャネル接続後にコントロールチャネル側でタイムアウト例外 が発生
- Server B では IIS の FTP サービスを有効化し、パッシブポートを「すべて」に近い広い範囲で開放
- Windows ファイアウォールは無効化済み
一見すると「ファイアウォールも切っているし、ポートも全部開けているからネットワーク原因ではなさそう」に見えますが、実際には以下のような要因が重なっていることが多くあります。
- Server A / B 間の OS・パッチレベルの差
- IIS FTP サービスの構成差(バインド、パッシブポート、FTPS の有無など)
- 社内ルーター・UTM・クラウド側ロードバランサなどの動作差
- FTP クライアント(C# コード)の接続モード設定差
ここから、実際の調査・解決に使える観点を体系的に見ていきます。
FTP タイムアウト問題を理解するための基礎知識
原因を切り分ける前に、FTP の「コントロールチャネル」と「データチャネル」の違いを簡単に整理しておきます。
| 項目 | コントロールチャネル | データチャネル |
|---|---|---|
| 役割 | ログイン、コマンド送信(LIST / RETR / STOR など) | 実際のファイルデータ転送 |
| ポート | 通常は 21/TCP(FTPS 明示的モードでも同様) | アクティブ: サーバー側 20/TCP パッシブ: サーバー側の「パッシブポート範囲」から動的に選択 |
| 問題の出方 | ログインに失敗、コマンド送信で固まる | ファイル一覧取得やアップロード・ダウンロード時にタイムアウト |
| 原因になりがちなもの | 認証設定、FTPS ハンドシェイク、SSL/TLS ポリシー | ファイアウォール・NAT・UTM による動的ポートブロック |
今回のように「データチャネル接続までは進むが、その後コントロールチャネル側でタイムアウトする」場合、多くはデータ転送中にネットワーク機器がセッションを切断してしまっている、またはFTPS の暗号化周りでタイムアウトが発生していることが多いです。
まず確認すべき Server A / B の環境差
意外と見落とされがちですが、「OS バージョン」「更新プログラム」「.NET ランタイム」の違いだけで挙動が変わるケースは少なくありません。特に Windows Server 2016 と 2019 の間では、TLS の既定設定や I/O 関連の挙動が異なる部分があります。
OS / 更新プログラムの差を揃える
最初に、Server A / B の OS 情報を比較します。
| 確認項目 | 確認方法(例) | ポイント |
|---|---|---|
| エディション / バージョン | サーバー上で winver を実行 / systeminfo を確認 | 2016 / 2019 の違いだけでなく、同じ 2019 でもビルド番号が大きく異ならないかを見る |
| 累積更新プログラム | 設定 > 更新とセキュリティ または systeminfo | Server A には適用済みだが、Server B には未適用のパッチがないか確認 |
| IIS のバージョン | PowerShell で Get-WindowsFeature Web-* などを確認 | IIS のメジャーバージョンは同じでも、実際のモジュール構成が違うことがある |
FTP に関係しそうな修正(FTPS 関連、TCP スタック関連など)が Server A だけに入っている場合、まずは更新プログラムをそろえるのが安全です。
.NET Framework / ランタイムのバージョン差
C# 製の FTP クライアント(多くは FtpWebRequest やサードパーティライブラリ)を使う場合、.NET ランタイムのバージョンで TLS の既定バージョンや例外の出方が変わることがあります。
- Server A は .NET Framework 4.8
- Server B は .NET Framework 4.6 など
といった差があれば、まず .NET Framework を最新まで揃えることを検討してください。
特に FTPS(明示的 / 暗黙的)を利用している場合、以下のようなコードで TLS バージョンを明示してみると現象が変わるケースがあります。
ServicePointManager.SecurityProtocol =
SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
var request = (FtpWebRequest)WebRequest.Create("ftp://example.com/test.txt");
request.Method = WebRequestMethods.Ftp.UploadFile;
request.UsePassive = true; // パッシブモード
request.EnableSsl = true; // FTPS の場合
Server B だけで例外が変わるようであれば、OS 側の TLS 設定や証明書チェーンの不整合が疑われます。
IIS FTP サービス側の基本チェックポイント
次に、IIS の FTP サイト構成そのものを整理していきます。Server A / B で下記のような表を埋めていくと、差分が見えやすくなります。
| 項目 | Server A(正常) | Server B(問題) | 確認ポイント |
|---|---|---|---|
| FTP サイトバインド | 例: 192.168.1.10:21 | 例: 全ての未割り当て:21 | 正しい IP で待ち受けているか。IPv6 が不要なら無効化してみる |
| パッシブポート範囲 | 例: 50000–51000 | 例: 1024–65535 | 最小限の範囲に絞り、同範囲をネットワークファイアウォールでも許可しているか |
| FTP ファイアウォール サポート | 外部 IP 指定済み | 未設定 | NAT 越えの場合はパブリック IP を明示しているか |
| 認証方式 | 基本認証 / 匿名認証 | 基本認証のみ / 他 | クライアントの想定と合っているか、IIS 側と NTFS 権限が矛盾していないか |
| FTPS の有無 | 平文 FTP または FTPS 明示的 | 強制 FTPS | 暗号化必須設定が原因で、古いクライアントが失敗していないか |
FTP サイトのバインド設定
特に複数 IP アドレス・複数 NIC を持つサーバーでは、FTP サイトのバインド設定により「意図していない IP で待ち受けている」ケースがあります。
- Server A は特定の IP アドレスにだけバインド
- Server B は「すべての未割り当て」にバインドしている
このような場合、負荷分散装置や NAT 装置との相性で、特定の経路からのみパッシブポートが開かないことがあります。一度、Server B も Server A と同じ IP アドレスに明示的にバインドし、挙動が変わるか確認すると良いでしょう。
パッシブポート範囲の設定と開放
「パッシブポートを 1024–65535 すべて許可」といった設定は、見た目上は「広く開けているから安全」と感じますが、現実には次のような問題を招きやすくなります。
- 社内 UTM が「不審な高番ポート通信」と判断し、動的にブロックしてしまう
- クラウド LB / セキュリティグループがルール数制限に引っ掛かり、実際にはごく一部しか開いていない
- 障害時の切り分けが極端に難しくなる
おすすめは、以下のように必要最小限のポート範囲を決めて固定することです。
- IIS マネージャーで FTP サイトを選択
- 「FTP ファイアウォール サポート」を開く
- 「データチャネルポート範囲」に例として
50000-51000等の狭い範囲を指定 - 同じ範囲を、サーバー OS のファイアウォール(使用する場合)およびネットワーク機器で許可
Windows ファイアウォールを有効にする場合は、PowerShell で以下のようなルールを追加できます。
New-NetFirewallRule -DisplayName "FTP Passive Ports" `
-Direction Inbound -Protocol TCP `
-LocalPort 50000-51000 -Action Allow
「Server B では Windows ファイアウォールを無効化している」場合でも、外側の UTM / FW がこの範囲を閉じていることが多いので、ネットワーク担当者に必ず確認しましょう。
NAT 越え時の外部 IP アドレス設定
FTP を NAT 越えで利用する場合、IIS の「FTP ファイアウォール サポート」で外部(パブリック)IP を明示しないと、パッシブモードの接続先 IP としてプライベート IP がクライアント側に通知されてしまうことがあります。
Server A では偶然、FTP サーバーにグローバル IP が直接付与されている、または FTP ALG(アプリケーションゲートウェイ)がうまく変換してくれていても、Server B では同様の環境が用意されていない、というケースは非常に多く見られます。
もし Server B が DMZ の内側にあり、外部公開は別のルーターで行っている場合は、必ず外部 IP を設定して再テストしてみてください。
認証・承認規則と NTFS 権限
FTP 接続自体は成功しているのに、ファイル一覧取得やアップロード直後にタイムアウトする場合、IIS 側の承認規則と NTFS 権限が微妙に噛み合っていないケースがあります。
- IIS の「FTP 認証」で匿名認証が有効だが、「FTP 承認規則」で匿名ユーザーが許可されていない
- 認証は成功するが、NTFS のフォルダ権限が読み取り専用で、書き込み時に例外が発生する
このような不整合があると、クライアントから見ると「途中で何かが固まったように見える」ことがあり、タイムアウトと誤認しがちです。Server A と Server B の承認規則・フォルダ権限を比較し、完全に同じになるように揃えてから再テストするのが有効です。
FTPS(SSL/TLS)利用時の注意点
FTPS を有効にしている環境では、暗号化ポリシーの違いが原因で接続が途中で止まることがよくあります。
- Server B だけ TLS 1.0 / 1.1 を無効化しており、古いクライアントが TLS 1.2 に対応していない
- Server B のみ強い暗号スイートのみ許可しており、ハンドシェイクに時間がかかってタイムアウトする
一時的な切り分けとして、以下のような方法があります。
- Server B 側で FTPS を「任意」にし、クライアントから平文 FTP で接続してみる
- C# 側で
EnableSsl = falseにして挙動を比較する
平文 FTP では問題が再現しない場合、FTPS の設定(証明書、TLS バージョン、暗号スイート)を重点的に見直してください。
ネットワーク/セキュリティ機器の確認ポイント
「Windows ファイアウォールは無効化したのにタイムアウトする」場合、ほぼ確実にサーバーの外側に原因があります。よく問題になる機器と症状の例をまとめます。
| 機器 | よくある設定 | よくある症状 |
|---|---|---|
| UTM / ファイアウォール | 21/TCP のみ許可、動的ポートは未許可 | ログインは成功するが LIST / RETR / STOR 時にタイムアウト |
| L3 スイッチ | 特定 VLAN 間の高番ポートを制限 | 同一セグメントからは成功するが、別セグメントからは失敗 |
| ロードバランサ | タイムアウト時間が短い/FTP 非対応 | 一定時間以上かかる転送だけが途中で切断される |
| FTP ALG 機能付きルーター | FTP ヘッダーを書き換えてくれるが、FTPS では機能しない | 平文 FTP は動くが FTPS ではタイムアウト |
パケットキャプチャでタイムアウト箇所を可視化する
原因を素早く特定したい場合は、Server B 側でパケットキャプチャを取得するのが最も確実です。例えば以下のような手順です。
- Wireshark などを Server B にインストール
- FTP 用の IP アドレスに対する通信をフィルタリング(例:
tcp port 21 or tcp portrange 50000-51000) - C# クライアントから問題の操作を実行
- タイムアウトしたタイミング前後で、以下のポイントを確認
- クライアントからの
SYNに対してサーバーがSYN-ACKを返しているか - その後の
ACKが届いているか(3 ウェイハンドシェイク完了) - どこかのタイミングで
RSTや ICMP エラーが返っていないか
もしサーバーからの SYN-ACK が途中で消えている場合、その区間にあるネットワーク機器が通信を遮断している可能性が高くなります。
クライアント側(C#)からできる切り分け
サーバー側の設定だけでなく、C# の FTP クライアントコード側でも、いくつか試せる切り分けポイントがあります。
パッシブモード / アクティブモードの切り替え
FtpWebRequest を使用している場合、UsePassive プロパティで接続モードを切り替えられます。
var request = (FtpWebRequest)WebRequest.Create("ftp://server-b.example.com/");
request.Credentials = new NetworkCredential("user", "password");
request.Method = WebRequestMethods.Ftp.ListDirectory;
// パッシブモードを試す
request.UsePassive = true;
// 必要に応じてアクティブモードも試す
// request.UsePassive = false;
具体的には、以下のような見方ができます。
- UsePassive = true だけが失敗する → パッシブポートの開放不足や NAT 設定を重点的に確認
- UsePassive = false だけが失敗する → クライアント側への逆向き接続(アクティブモード)が社内ポリシーで禁止されている可能性が高い
通常、インターネット越しの場面ではパッシブモード利用が推奨されるため、「パッシブで動かすにはどうすべきか」という観点でサーバー側・ネットワーク側を調整していくのが現実的です。
FTPS を一時的に無効化してテストする
明示的 FTPS を利用している場合、切り分けとして一時的に暗号化を無効化するのも有効です。
// FTPS を利用している場合
request.EnableSsl = true;
// 切り分けのため一時的に無効化
request.EnableSsl = false;
平文 FTP では問題が再現しないのであれば、FTPS の証明書・TLS バージョン・暗号設定のいずれかが Server B だけ異なっている可能性が高くなります。
タイムアウト値や KeepAlive の確認
長時間かかる大容量転送でのみタイムアウトする場合、クライアント側のタイムアウト値や KeepAlive 設定が影響している場合もあります。
ReadWriteTimeoutの既定値が短すぎるKeepAliveがfalseになっており、コネクションが使い回されない
Server A / B のクライアントコードが本当に同一なのか、ビルド構成や設定ファイルも含めて再チェックしてみましょう。
Server A / B の差分をあぶり出す比較チェックリスト
ここまでの内容を踏まえ、実際の調査で使いやすい比較表の例を紹介します。実環境では、実際の値を埋めていきながら原因を絞り込んでいきます。
| カテゴリ | 項目 | Server A | Server B | 差分メモ |
|---|---|---|---|---|
| OS | OS バージョン / ビルド | 2016 / Build xxxx | 2019 / Build yyyy | ビルド差あり。更新プログラムの差を要確認 |
| OS | .NET Framework バージョン | 4.8 | 4.6.2 | Server B の更新・再テストを検討 |
| IIS | FTP サイトバインド | 192.168.1.10:21 | 未割り当て:21 | Server B も同じ IP に固定してテスト |
| IIS | パッシブポート範囲 | 50000–51000 | 1024–65535 | Server B も 50000–51000 に揃える |
| ネットワーク | FW/UTM のポリシー | 21 + 50000–51000 許可 | 21 のみ許可 | Server B 経路の FW でポート開放要 |
| クライアント | UsePassive / EnableSsl | UsePassive=true / EnableSsl=false | UsePassive=true / EnableSsl=true | FTPS+パッシブが Server B だけ失敗していないか確認 |
このような表を埋めていくと、「Server B だけパッシブポートが外部 FW で閉じていた」「Server B だけ FTPS 強制になっていた」といった差分に気付きやすくなります。
ログとコマンドを使った追加デバッグ Tips
IIS FTP ログの詳細化と sc-win32-status の確認
FTP サイトのログを「詳細」にし、以下のようなフィールドを出力するように設定します。
- sc-status / sc-substatus
- sc-win32-status
- cs-host / cs-username / c-ip / s-ip など
ログを確認する際は、タイムアウトが発生した時間帯のエントリを洗い出し、sc-win32-status の値を重点的に確認します。
- 64(ネットワーク名が削除されました)など → 通信途中でどこかが接続を切断
- 10060(接続がタイムアウト)など → 受信・送信のどちらかが応答せずタイムアウト
Server A と Server B のログを同じ操作で比較すると、「Server B だけ sc-win32-status が 10060 になっている」といった違いが見えてきます。
PowerShell の Test-NetConnection でポート疎通を確認
サーバー側のポート開放を手軽に確認するには、PowerShell の Test-NetConnection コマンドレットが便利です。Server B の FTP サーバーに対して、クライアント側または同一ネットワーク内の別マシンから次のように実行します。
# 制御ポート 21 の疎通確認
Test-NetConnection -ComputerName server-b.example.com -Port 21
# パッシブポート範囲のうち一部を確認
Test-NetConnection -ComputerName server-b.example.com -Port 50000
Test-NetConnection -ComputerName server-b.example.com -Port 50001
ここで、Server A 宛てでは成功するが Server B 宛てでは特定のポートだけ失敗する場合、ネットワーク機器側のポリシー差が疑われます。
同一サブネット内からのテストでインターネット要因を排除
インターネット経由で接続している場合は、まず同一サブネット内にテスト用の FTP クライアントマシンを置き、内部から Server B に接続してみると切り分けがしやすくなります。
- 内部からは問題なく接続できるが、インターネット越しだと失敗 → 外部向けの FW / NAT 設定に問題
- 内部からでも同じようにタイムアウト → サーバー OS / IIS 設定に問題
この二段階テストにより、「サーバー内部の問題か」「ネットワーク経路の問題か」を効率よく判定できます。
よくある原因パターンと対処例
最後に、実際の現場でよく遭遇するパターンを、Server A では成功・Server B では失敗という構図で整理します。
パターン 1: パッシブポートが外部ファイアウォールで閉じている
- Server A: DMZ ではなく内部ネットワーク内にあり、クライアントも同一ネットワーク内
- Server B: DMZ に設置され、インターネットから UTM 経由で接続
この場合、Server B では 21/TCP のみ許可され、パッシブポート範囲(例: 50000–51000)が許可されていないことがよくあります。
対処:
- IIS でパッシブポート範囲を狭く固定(例: 50000–50100)
- 同範囲を UTM / FW で明示的に許可
- 必要に応じてソース IP を絞り、セキュリティと両立させる
パターン 2: FTPS 強制 + 古いクライアントとの組み合わせ
- Server A: 平文 FTP または FTPS 任意
- Server B: FTPS 必須 + TLS 1.2 のみ許可
この場合、古い .NET Framework やサードパーティ FTP ライブラリを利用しているクライアントでは、TLS 1.2 に対応していない、または既定で TLS 1.0 を使おうとして失敗し、タイムアウトに見えることがあります。
対処:
- クライアント側で TLS 1.2 を明示する(
ServicePointManager.SecurityProtocolの設定など) - 一時的に Server B の FTPS 必須設定を緩和し、平文 FTP で再テスト
- .NET Framework を最新バージョンに更新
パターン 3: FTP ALG(アプリケーションゲートウェイ)の思わぬ影響
- Server A: 平文 FTP のみ、ALG がうまくパケットを書き換えてくれる
- Server B: FTPS を利用しており、ALG が暗号化されたペイロードを解釈できない
多くのルーターや UTM に搭載されている FTP ALG は、FTP コマンドのペイロードを書き換えることで、NAT 越えでもアクティブモードを動かしやすくしてくれる機能です。しかし、FTPS のようにペイロードが暗号化されると、それが逆に邪魔をしてしまう場合があります。
対処:
- FTP ALG 機能を無効化し、パッシブモード + パッシブポート開放の組み合わせに切り替える
- FTPS を利用する場合は、基本的にパッシブモードに統一する
パターン 4: Server B のみセキュリティソフト / エージェントが導入されている
エンドポイントセキュリティ製品(アンチウイルス、EDR など)が Server B のみに導入されており、FTP のデータ転送を検査することで通信が遅延・タイムアウトするケースもあります。
対処:
- Server B のセキュリティ製品のログを確認し、FTP 通信が検査対象になっていないか確認
- 一時的にリアルタイム保護を無効化して再テスト(検証環境で実施)
- FTP ポート / プロセスを除外設定に追加
サポート・フォーラムの活用ポイント
どうしても原因が特定できない場合は、以下のような情報を整理した上で、IIS 関連フォーラムや .NET 開発者向け Q&A サイトに質問するのも有効です。
- Server A / B の OS バージョン、ビルド、更新プログラム一覧
- IIS FTP サイトの構成(バインド、パッシブポート範囲、FTPS 設定、認証方式など)
- FTP ログ(該当時間帯の
sc-status,sc-substatus,sc-win32-statusを含む) - UTM / FW のポリシー概要(21/TCP、パッシブポートの扱い)
- C# クライアント側の主要コード(接続先、UsePassive、EnableSsl、タイムアウト値など)
これらをセットで提示することで、第三者からも原因を推測しやすくなり、最終的な解決にたどり着きやすくなります。
まとめ: OS・IIS・ネットワークを「Server A と同じ」に近づければ原因に近づく
Windows Server 2016 / 2019 で、同じ C# 製 FTP クライアントが Server A では正常なのに Server B ではタイムアウトする問題は、一見すると複雑ですが、次の観点で地道に差分を埋めていくことで、多くの場合原因を特定できます。
- OS / .NET / IIS バージョンと更新プログラムを揃える
- IIS FTP のバインド、パッシブポート、FTPS 設定を Server A と同じ構成に近づける
- ネットワーク機器(UTM / FW / ルーター)のポリシー差を洗い出し、必要なポートを明示的に開放する
- C# 側の UsePassive / EnableSsl / タイムアウト設定を切り替えて、どの組み合わせで失敗するかを把握する
- FTP ログとパケットキャプチャ、Test-NetConnection で「どこまで通信が届いているか」を可視化する
最終的には、Server A と Server B の設定を一つひとつ比較し、差分を丁寧に潰していくことが最も確実なアプローチです。本記事のチェックリストとコマンド例を活用しながら、FTP タイムアウト問題の原因特定と再発防止に役立てていただければ幸いです。

コメント