Direct Connectで失敗して学んだ|VPN併用で乗り切った本番選定の失敗と判断基準
オンプレ連携で3ヶ月悩んだDirect ConnectとVPN選び。搬入2ヶ月の落とし穴と、結局VPN先行+DC並行で対応した経験から、2026年の実装判断基準をまとめました。
Direct Connect vs Site-to-Site VPN|本番選定で失敗した話と2026年の実装判断基準
先日プロジェクトで、オンプレミスのシステムとAWSを繋ぐ際に、Direct ConnectとSite-to-Site VPNのどっちを選ぶかで3ヶ月悩んだんですよね。結局失敗もしたし、いろいろ学んだのでまとめておきます。
選定で失敗した話|最初はDirect Connectで進めていた
うちのチームは最初、「遅延が重要だからDirect Connectだ」という単純な判断で進めていたんです。営業からも「高速・安定」って言われてたし、金銭的余裕もあったから。
でも実装が進むと、搬入から開通まで2ヶ月かかるという現実に直面。プロジェクト予定を組み直すハメになりました。さらに、オンプレ側のLOA-CFA書類の準備も予想外に手間で、「あれ、こんなに時間かかるんだ」って本気で後悔したのを覚えてます。
結局うちは、VPNで先行開発を進めながら、Direct Connectを並行実装するという苦肉の策を取りました。正直マジで大変でした。
Timeline:
- Week 1-2: Direct Connect LOA-CFA準備開始
- Week 3-4: 施設側とのスケジューリング(ここで1ヶ月ズレる)
- Week 8-10: 物理搬入・ケーブル敷設
- Week 9-12: VPN先行で開発継続
- Week 12: Direct Connect本番投入
2026年の実装判断基準
遅延・スループット比較
実際にチームで測定してみた結果がこちら。
| 項目 | Site-to-Site VPN | Direct Connect | AWS Direct Connect+VPN冗長 |
|---|---|---|---|
| 平均遅延(ms) | 20-50ms | 5-15ms | 5-15ms(フェイルオーバー時20-50ms) |
| スループット | 〜1.25 Gbps | 1-100 Gbps | スケーラブル |
| 導入期間 | 1-2週間 | 6-8週間 | 8-12週間 |
| 月額コスト | $32 | $0.30/時間 + $0.02/GB | $0.60/時間 + $0.04/GB |
| セットアップ手数料 | $0 | $5000-10000 | $10000-20000 |
| 安定性 | 99.9%(AWS側) | 99.99%+ | 99.99%+ |
ここで気づく一番重要な点は、遅延だけで判断するなってことなんですよね。
実測データで見る
実際にうちのチームが測定した遅延分布を見るとこんな感じです。
xychart-beta
title "遅延測定(1000回サンプル)"
x-axis [Site-to-Site VPN, Direct Connect]
y-axis "遅延(ms)" 0 --> 100
line [35, 10]
これだけ見ると「Direct Connectの方が3倍速い」って思うんですが、実運用ではVPN側の変動幅(20-50ms)でも許容できるケースがほとんどなんです。アプリケーションレベルでは、この差が体感されることはまずありません。
VPNで十分なケース|うちのチームで判断した基準
正直、うちのプロジェクトではVPNで本当に十分でした。以下のポイントを満たしてたからです。
1. スループット要件が1 Gbps以下
うちのオンプレシステムから送られてくるデータが、ピーク時で200-300 Mbps程度。VPN(最大1.25 Gbps)で十分なんですよ。
2. 遅延が数秒の許容範囲内
バッチ処理がメインで、リアルタイムジョブがほぼない。20-50msの遅延差なんて、アプリケーションレベルでは観測できないレベルです。
3. 導入時間が大事
プロジェクト開始時点で「4ヶ月以内に本番」という制約があった。VPNなら1週間で繋げるのが救い。
4. コストプレッシャーが強かった
年間で比較すると、かなり大きな差が出ます:
- VPN: $32 × 12 = $384 + データ転送費 ≈ $5,000-10,000/年
- Direct Connect: $0.30 × 24 × 365 = $2,628 + データ転送費 ≈ $20,000-50,000/年
なんでこんなに違うのかってと、Direct Connectは常時接続料金がある。VPNはインターネット経由だから、AWS側のデータ転送料金はかかるけど、比較的安く済むんですよね。
Direct Connectが必須なケース
ただ、逆に「これがあるならDirect Connectでいこう」っていう判断基準も当然あります。
1. 遅延が1桁ms必須
金融取引、リアルタイムシミュレーション、HFT(高頻度取引)みたいなやつだと、20msの遅延は致命的になる。この場合はDXは避けられません。
2. スループット5 Gbps超えの常時接続
大規模データセンター連携、動画配信、IoTセンサーからの大量データ取得。VPNじゃ物理的に無理です。
3. 規制要件でインターネット経由が禁止
金融機関、医療、政府系だと「クローズドネットワーク必須」って契約で決まってる場合がありますよね。この場合も選択肢はDXだけ。
4. 既にDirect Connectのポート契約がある
これが隠れた大事なポイント。社内に複数VPCがあって、既に1本Direct Connectが引かれてるなら、追加VPCを同じポートに繋ぐだけ(Virtual Interface追加)で済む。新規で引く必要がないから圧倒的に安い。
2026年的な実装パターン|ハイブリッドが実は強い
うちが最終的に落ち着いたのは、VPN + Direct Connectの冗長構成です。これがマジで賢い選択だったんですよ。
graph TB
subgraph OnPrem["オンプレミスデータセンター"]
GW["Corporate Gateway<br/>BGP AS:65000"]
FW["Firewall"]
end
subgraph Internet["インターネット"]
ISP["ISP"]
end
subgraph AWS["AWS"]
subgraph VPC["VPC (10.0.0.0/16)"]
TGW["Transit Gateway<br/>AS:64512"]
subgraph AZ1["AZ-a"]
EC2A["EC2 Instance<br/>10.0.1.0/24"]
end
subgraph AZ2["AZ-c"]
EC2B["EC2 Instance<br/>10.0.2.0/24"]
end
end
subgraph Hybrid["ハイブリッド接続"]
VGW1["Virtual Private Gateway<br/>VPN"]
DX["Direct Connect<br/>Virtual Interface"]
end
end
GW -->|BGP Session| FW
FW -->|IPSec Tunnel<br/>Site-to-Site VPN| VGW1
FW -->|1Gbps Dedicated<br/>Direct Connect| DX
VGW1 --> TGW
DX --> TGW
TGW --> EC2A
TGW --> EC2B
style OnPrem fill:#e1f5ff
style AWS fill:#f3e5f5
style Hybrid fill:#fff3e0
この構成の良いところ、いろいろあるんですよ:
フェイルオーバー自動化
BGPで優先度制御ができるので、通常はDirect Connect経由で通す。DX障害時は自動的にVPN経由にフェイルオーバーしちゃう。手動切り替えなんて古い話です。
段階的投資
初期はVPNだけで開発。トラフィック増加に応じてDXを追加する。コスト最適化の余地もある。焦って全部構築する必要ないんです。
実装がシンプル
VPN: 1-2週間で本番稼働できる。DX追加: 既存VPN維持しながら並行実装できる。リスク分散がイケてます。
実装コード例|VPN + DXのBGP設定
AWS側の設定(Terraform)
# Transit Gateway
resource "aws_ec2_transit_gateway" "main" {
description = "Hybrid connectivity hub"
default_route_table_association = "disable"
default_route_table_propagation = "disable"
tags = {
Name = "hybrid-tgw"
}
}
# Virtual Private Gateway (for VPN)
resource "aws_vpn_gateway" "main" {
vpc_id = aws_vpc.main.id
amazon_side_asn = 64512
tags = {
Name = "vpn-gateway"
}
}
# Customer Gateway (オンプレ側ゲートウェイ)
resource "aws_customer_gateway" "onprem" {
bgp_asn = 65000
public_ip = var.onprem_public_ip # 固定IP必須
type = "ipsec.1"
tags = {
Name = "onprem-gateway"
}
}
# VPN Connection
resource "aws_vpn_connection" "main" {
vpn_gateway_id = aws_vpn_gateway.main.id
customer_gateway_id = aws_customer_gateway.onprem.id
type = "ipsec.1"
static_routes_only = false # BGP有効
options {
static_routes_only = false
}
tags = {
Name = "vpn-to-onprem"
}
}
# Transit Gateway Attachment (VGW)
resource "aws_ec2_transit_gateway_vpc_attachment" "vpn" {
transit_gateway_id = aws_ec2_transit_gateway.main.id
vpn_gateway_id = aws_vpn_gateway.main.id
transit_gateway_default_route_table_association = true
transit_gateway_default_route_table_propagation = true
}
# Direct Connect Virtual Interface (Private VIF)
resource "aws_ec2_customer_gateway" "dx" {
bgp_asn = 65000
ip_address = var.onprem_dx_ip # Direct Connectのカスタマー側IP
type = "ipsec.1"
}
resource "aws_ec2_transit_gateway_direct_connect_gateway_attachment" "main" {
transit_gateway_id = aws_ec2_transit_gateway.main.id
direct_connect_gateway_id = var.dcgw_id
}
# BGP Route Preference制御
resource "aws_ec2_transit_gateway_route" "default" {
destination_cidr_block = "0.0.0.0/0"
transit_gateway_route_table_id = aws_ec2_transit_gateway.main.association_default_route_table_id
transit_gateway_attachment_id = aws_ec2_transit_gateway_vpc_attachment.vpn.id
blackhole = false
}
オンプレ側の設定(Cisco IOS-XE例)
! BGP設定
router bgp 65000
bgp log-neighbor-changes
neighbor 169.254.10.1 remote-as 64512
neighbor 169.254.11.1 remote-as 64512
address-family ipv4
neighbor 169.254.10.1 activate
neighbor 169.254.11.1 activate
network 172.16.0.0 mask 255.255.0.0
exit-address-family
exit
! IPSec IKEv2設定
ipsec profile AWS-PROFILE-1
set pfs group14
set security-association lifetime seconds 28800
set security-association lifetime kilobytes unlimited
set transform-set AWS-TRANSFORM-SET
set log-status
exit
! Tunnel Interface
interface Tunnel1
ip address 169.254.10.2 255.255.255.252
ip mtu 1436
no ip split-dns
tunnel source <CUSTOMER_GW_PUBLIC_IP>
tunnel destination <AWS_VGW_ENDPOINT_1>
tunnel mode ipsec ipv4
tunnel protection ipsec profile AWS-PROFILE-1
no shut
exit
! Route Preference(優先度制御)
route-map AWS-PRIMARY permit 10
set local-preference 200
exit
route-map AWS-BACKUP permit 10
set local-preference 100
exit
フェイルオーバー検証スクリプト
import boto3
import subprocess
import time
from datetime import datetime
class HybridConnectivityMonitor:
def __init__(self):
self.ec2 = boto3.client('ec2', region_name='ap-northeast-1')
self.cloudwatch = boto3.client('cloudwatch')
def check_vpn_status(self):
"""VPN接続状態確認"""
response = self.ec2.describe_vpn_connections()
vpn_status = {
conn['VpnConnectionId']: conn['State']
for conn in response['VpnConnections']
}
return vpn_status
def check_dx_status(self):
"""Direct Connect VIF状態確認"""
response = self.ec2.describe_virtual_interfaces()
dx_status = {
vif['virtualInterfaceId']: vif['virtualInterfaceState']
for vif in response['virtualInterfaces']
}
return dx_status
def simulate_dx_failure(self, vif_id):
"""DX障害をシミュレート"""
print(f"[{datetime.now()}] Simulating DX failure for {vif_id}")
# 実際にはテスト用VIFを使用
# 本番では絶対やらない!
def monitor_bgp_routes(self):
"""BGPルート確認(EC2インスタンス経由)"""
# SSM Session Manager経由でオンプレ側をpingテスト
onprem_subnet = "172.16.0.0/24"
result = subprocess.run(
f"ping -c 5 172.16.0.1",
shell=True,
capture_output=True,
text=True
)
return "0% packet loss" in result.stdout
def failover_test(self):
"""フェイルオーバーテスト"""
print(f"\n=== Failover Test Started ===")
# 1. 初期状態確認
print("\n[Step 1] Baseline connectivity check")
vpn_status = self.check_vpn_status()
dx_status = self.check_dx_status()
print(f"VPN Status: {vpn_status}")
print(f"DX Status: {dx_status}")
# 2. レイテンシ測定
print("\n[Step 2] Latency measurement (normal operation)")
ping_result = subprocess.run(
"ping -c 10 -W 100 172.16.0.1",
shell=True,
capture_output=True,
text=True
)
# レイテンシパース処理
latencies = [
float(line.split('time=')[1].split('ms')[0])
for line in ping_result.stdout.split('\n')
if 'time=' in line
]
print(f"Average latency: {sum(latencies)/len(latencies):.2f}ms")
# 3. 接続性テスト
print("\n[Step 3] Connectivity test")
if self.monitor_bgp_routes():
print("✓ Connectivity OK")
else:
print("✗ Connectivity FAILED")
# 4. フェイルオーバー効果検証
# DX障害時のVPN自動フェイルオーバー
print("\n[Step 4] Simulating DX failure (not actually failing, just testing BGP behavior)")
print("Waiting for BGP convergence...")
time.sleep(30)
# 5. フェイルオーバー後の測定
print("\n[Step 5] Connectivity after failover")
ping_result_failover = subprocess.run(
"ping -c 10 -W 100 172.16.0.1",
shell=True,
capture_output=True,
text=True
)
latencies_failover = [
float(line.split('time=')[1].split('ms')[0])
for line in ping_result_failover.stdout.split('\n')
if 'time=' in line
]
print(f"Failover latency: {sum(latencies_failover)/len(latencies_failover):.2f}ms")
print(f"Latency increase: {(sum(latencies_failover)/len(latencies_failover)) - (sum(latencies)/len(latencies)):.2f}ms")
# 6. CloudWatch メトリクス送信
self.cloudwatch.put_metric_data(
Namespace='HybridConnectivity',
MetricData=[
{
'MetricName': 'PrimaryPathLatency',
'Value': sum(latencies)/len(latencies),
'Unit': 'Milliseconds'
},
{
'MetricName': 'BackupPathLatency',
'Value': sum(latencies_failover)/len(latencies_failover),
'Unit': 'Milliseconds'
}
]
)
print("\n=== Failover Test Complete ===")
if __name__ == "__main__":
monitor = HybridConnectivityMonitor()
monitor.failover_test()
2026年時点での新しいオプション
ちなみに2026年は、Direct Connect Gateway (DCGW)とTransit Gatewayの組み合わせが標準になってきました。昔は複雑だったけど、今は運用がマジで楽になってるんです。
Direct Connect Gatewayを使うと、こんなメリットがあります:
複数VPCを1つのDXで接続可能
昔は「VPC毎にDX1本必須」だったんですよ。今は1本のDXで複数VPC接続できちゃう。スッキリします。
オンプレ連携も同じDXで統合
オンプレ-AWS間のDX、AWS-AWS間のDX、全部1つのDCGWで管理できる。複数キャリアにも対応できるし、冗長性も高まる。
BGP優先度が自動化される
わざわざ手動設定しなくてもASPathで自動調整されるようになった。運用負荷が大幅に下がりました。
コスト削減のコツ
実運用で気づいたコスト削減ポイント、いくつかあります。
1. Data Transfer料金が9割
Direct Connectの月額$0.30/時間は微々たるもの。問題はデータ転送料金なんですよ。
月1TB転送:$0.30 × 730時間 + 1TB × $0.02 = $218 + $20 = $238
年間10TB:同額 × 12 = $2,856
ところがVPN経由だと:
VPN: $0 (VPN接続料無料)
AWS-Internet egress: 1TB × $0.09 = $90/TB
月1TB: $90 × 12 = $1,080/年
あ、VPNの方が高い…? 実は転送量が多いと逆転するんです。月3TB超えたあたりからDXの方がお得になり始める。
2. 実測で判断が大事
うちのチームは最初、VPN + DXで合計年30万円だと予想してました。実際に運用してみたら:
実測月平均: 200GB/月
VPN年額: 200GB × 12 × $0.09 = $2,160
DX年額: $2,628 + (200GB × 12 × $0.02) = $2,628 + $48 = $2,676
合計: $4,836
ほぼVPN。DX冗長化のメリットは「月100万円削減できる障害回避」だから、SLA要件とのバランスで決まる。単純にコスト削減だけじゃ判断できないんですよね。
運用で気づいたこと
1. VPN接続ドロップが予想外に多い
最初「ノイズレベル」だと思ってたんですけど、うちのISPの場合月1-2回VPN接続が30秒ほどドロップするんです。結構あります。
ISP側に問い合わせたら「IPSecはUDP 500/4500ポートなので、中間ネットワークでブロックされることがある」って言われました。NATトラバーサル設定を強化したら減ったけど、完全には0にできないんですよね。この辺は覚悟しておくべき。
2. オンプレ側のファイアウォール設定が地雷
VPNトンネルが繋がった〜と思ったら、FW設定漏れでデータが通らない。地雷です。こういうやつ:
# NGな設定
acl 101 permit ip any 10.0.0.0 0.0.255.255 # AWSのVPCネットワーク
# OKな設定(Dynamic Cryptomap経由)
acl 101 permit ip 172.16.0.0 0.0.255.255 10.0.0.0 0.0.255.255
VPNは両端でACLの順序と優先度が重要。オンプレ側の変更に数日かかることもあります。ネットワークチームとの調整が鍵ですね。
3. Direct Connectの接続工事は思ったより複雑
ロケーション選定から光ファイバー敷設まで、AWS側と施設側と通信キャリアが全部関わります。スケジュール調整だけで2ヶ月。正直、予想の1.5倍かかったかな。
まとめ
-
VPN vs DXは二者択一ではない — VPN + DX冗長化が2026年の標準パターン。初期はVPNで迅速開発、トラフィック増加に応じてDX追加するのが賢明です。
-
遅延要件をちゃんと定義する — 「低遅延」は定義次第。5msと20msで判断は激変します。事前にベンチマークテストを実施してから判断しましょう。
-
コスト計算は月々のデータ転送量が鍵 — 月1TB未満ならVPN圧倒的安い。月10TB超えたらDXの検討開始が目安。実測が何より大事です。
-
フェイルオーバーはBGPで自動化 — 手動切り替えなんて古い。BGP設定で優先度制御して、障害時自動フェイルオーバー。運用負荷がマジで減ります。
-
オンプレ側の準備時間を侮るな — AWS側は1週間で繋げるけど、オンプレのネットワーク組織が動くのに2ヶ月。スケジュール管理を最優先に。ここで失敗するプロジェクト、本当に多いですよ。