クラウドにすべて置いてきた
〜iPadからゲーミングPCを召喚するまで〜
突然ですがわたし、ガジェットオタクなんです。
同じ趣味嗜好の方には共感していただけると思うのですが、
パソコンやタブレットって勝手にいつの間にか増殖しますよね!
気がついたら・・・
- ゲーミングWindows PC
- モバイルWindows PC
- Mac mini
- iPad×5台 など
この超カオスな「PC、タブレット多すぎ問題」をなんとかしたい。
そこから今回の話は始まりました。
わたしはこのカオスな部屋の風景に絶望し、徐々にミニマリストに憧れを持ち始めました。
そんなわたしの思い描く究極のガジェットとは
オールインワン(すべての機能が1台にまとまったもの)
なんです。
その究極の1台を探すため、検証を進める日々、この検証過程で物が増えてしまうのです。
いくら探しても究極の1台は存在しない・・・そこで発想を逆転させます。
自分で作っちゃえ!
ハードから作る技術なんてないわたしでも仮想的に作っちゃえば可能なんです。
そう、クラウドならね!
ゲーム用のPCも、モバイル用のWindows環境もぜんぶクラウドに置いてしまいましょう。
そして手元にはiPad1台だけを残して
遊びたいときも、作業したいときも、iPadからクラウドのマシンを呼び出して使う。
そんな環境を、AWS上に「趣味&検証目的」で作ってみました。
この記事は、その過程をストーリー仕立て+ゆるめの技術解説でまとめたものです。
※あくまで個人利用の検証構成です。
実際に利用する場合はAWS・Microsoft・各ゲームの利用規約を必ずご自身で確認してください。
やりたいことの全体像
やりたいことをざっくり言うと、こんな構成です。
- クラウド上に「ゲームもできるWindowsマシン」を用意する
- AWS EC2(仮想マシン)
- OS は Windows Server 2022(安定性を評価して採用)
- GPU付きインスタンスでゲームも動かす
- iPadからゲームストリーミングで遊ぶ
- サーバー側:Sunshine
- iPad側:Moonlight
- 接続できるのは自分だけに制限
- 同じマシンをリモートデスクトップ(RDP)でも使う
- 使うときだけ起動して、終わったら削除
→ ランニングコストを最小化 -
iPadのショートカットから「どのインスタンスを起動するか」を選べる
- RDP用:
t3.xlarge - ゲーム(フルHDくらい):
g4dn.2xlarge - ゲーム(フルHDより高解像度):
g5.xlarge
- RDP用:
- スポットインスタンスを使用(AWSの余剰リソースを激安で使わせてもらう)
- 将来的には、起動ログと料金をDynamoDBに記録して可視化したい(現時点では未実装)
- ランニングコストは可能な限り削減する(遊び終わったら毎回不要なリソースは消す)
Step 1: まずはクラウドに「ゲームPCのベース」を作る
Windows Server 2022 を選んだ理由
クラウド側のOSには Windows Server 2022 を選びました。
- AWSが公式に提供していて扱いやすい
- ライセンス込みの料金なので、細かいライセンス計算を自分でしなくていい
- GPU付きインスタンスにもそのまま乗せ替えしやすい
- 実際に使ってみて、安定して動作してくれる印象
というあたりを評価しています。
補足:EC2とは
AWSが提供する「クラウド上の仮想マシン」です。
ローカルPCの代わりに、クラウドの中に Windows や Linux を立てて使えます。
ここで、
- Windowsの初期設定
- 日本語環境のセットアップ
- リモートデスクトップの有効化
などを行い、ゲームPCのベースを作っていきます。
Step 2: Sunshine と Moonlight と「同一ネットワーク」の壁
ゲームのストリーミングにはこちらを使いました。
- サーバー側(EC2):Sunshine
→ ゲーム画面をネットワーク越しに配信するソフト - クライアント側(iPad):Moonlight
→ Sunshineに接続して映像と操作を送受信するアプリ
Steam(PCゲーム配信プラットフォーム) と DDNS クライアント(後ほど説明)もサーバーに入れておきます。
「同一ネットワーク必須」の罠
最初にぶつかった問題がこれです。
iPad の Moonlight から、EC2 上の Sunshine にペアリングできない。
調べていくと、初回ペアリング時は“同じネットワーク”にいる必要があるらしい。
でも現実は、
- iPad:自宅(福岡)のWi-Fi(家庭内LAN)
- EC2:AWSのデータセンター(関東のどこか)
明らかに別世界です。
一瞬、
「じゃあ AWS のデータセンターまで LAN ケーブル引っ張るか……?」
と考えましたが、(冗談ですが)
さすがにそれは無理なので、別の方法を考えます。
VPNで「同じネットワークっぽく」見せる
採った手段は、
- 自宅にVPN用の入口を作る
- EC2をそのVPNに参加させる
という方法です。
補足:VPNとは?
VPNは、自宅とデータセンターを暗号化された“トンネル”でつなぎ、同じネットワークのように扱える仕組みです。
こうすることで、論理的には
- iPad
- EC2
が同じネットワーク上に見えるようになり、
Moonlightからの初回ペアリングが通るようになりました。
DDNSとは何か?なぜ必要なのか
ここで出てきた DDNS について、少しだけ説明しておきます。
普通にクラウドPCを立てると何が起きるか
AWSでEC2を起動すると、基本的には
- 起動のたびにグローバルIPアドレスが変わる
という挙動になります。
もちろん、Elastic IP という「固定IP」を使う方法もありますが、
- Elastic IP は 使っていない時に料金が発生する
ので、
「ランニングコストは可能な限り削減」という今回のポリシーに反するので使いません。
DDNSの仕組み
そこで使うのが DDNS(Dynamic DNS) です。
ざっくりいうと、
「
mypc.example.comという名前に、
今この瞬間の起動したクラウドPCのグローバルIPアドレスをひも付けてくれるサービス」
です。
- クラウドPCが起動したタイミングで
- 現在のグローバルIPアドレスをDDNSサービスに通知
- クライアント(iPadなど)は
- いつも
mypc.example.comに接続するだけでOK - 中身のIPアドレスは起動するたびに自動更新される
- いつも
という形になります。
IPアドレスは毎回変わっても、名前(ドメイン名)は変わらないので、
繋ぐ際にグローバルIPアドレスを調べる必要がなくなり便利です。
Step 3: AMI化して「ゲームPCのイメージ」を保存する
ある程度環境が整ったら、
一度スナップショットを取り、AMI(Amazon Machine Image) を作成します。
AMIとは
「この時点のサーバー状態をテンプレート化したもの」です。
新しいEC2インスタンスをAMIから起動すると、
そのときインストールされていたソフトや設定を引き継いで立ち上がってくれます。
この時点の構成は、
- Windows Server 2022(日本語環境)
- Steam インストール済み
- Sunshine インストール済み
- DDNSクライアント設定済み
という、「ゲームPCのイメージ」です。
このAMIを元に、
後でGPU付きインスタンス(g4dn, g5)を起動して使っていきます。

Step 4: iPadショートカットからゲームPCを召喚する
ここからは、「召喚ボタン」を作成していきます。
ショートカットでインスタンスタイプを選ぶ
iPad側では ショートカットアプリ を使っています。
ショートカットの実行時に
- どの用途で使うか?を選択
- RDP用:
t3.xlarge - ゲーム(フルHDくらい):
g4dn.2xlarge - ゲーム(フルHDより高解像度):
g5.xlarge
※GPU付きインスタンスの起動は初め制限がかかっているのでAWSに申請が必要です
- RDP用:
という形でインスタンスタイプを選べるようにし、
その値をAPIのパラメータとして送っています。
スポットインスタンスを使っているので、
-
g4dn.2xlargeやg5.xlargeのインスタンスタイプは昼間、よく利用されるようで「キャパシティ不足(空きリソースなし)」で起動できない・・・
ということもあります。※夜は比較的空いています
起動フローの裏側
起動の裏側はこんな流れです。
- iPadのショートカットから、API Gateway のURLを叩く
→ どのインスタンスを使いたいかパラメータで渡す - API Gateway が Lambda を呼び出す
- Lambda は
- 指定されたインスタンスタイプ
- 最新の AMI ID
- 呼び出し元のグローバルIPアドレス
を元に、CloudFormation用のパラメータを組み立てる
- CloudFormation テンプレート(S3に置いてある)を使ってEC2を起動
- 数分すると、Moonlightから接続できる状態になる
セキュリティグループでは
- Sunshine/Moonlight用のポート
- RDP用のポート(3389)
を開けつつ、接続元IPは「ショートカットを実行した時点のわたしのグローバルIPだけ」を許可するようにしています。
↓CloudFormationテンプレートはこんな感じ
AWSTemplateFormatVersion: '2010-09-09'
Description: "Moonlight EC2 instance with Elastic IP"
Parameters:
AmiId:
Type: AWS::EC2::Image::Id
Description: 使用するWindows AMI ID
InstanceType:
Type: String
Default: t3.xlarge
AllowedValues:
- g4dn.2xlarge # GPUを使ったゲーム用途向け
- g5.xlarge # GPUを使ったゲーム用途向け(高スペック)
- t3.xlarge # 軽量なRDP用
Description: 使用目的に応じてインスタンスタイプを選択
ClientIp:
Type: String
Description: 接続元のグローバルIPアドレス(CIDR形式、例:xxx.xxx.xxx.xxx/32)
Resources:
# 必要なポートのみを接続元IPに限定して開放するセキュリティグループ
InstanceSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Security group for Moonlight EC2
VpcId: !Ref AWS::NoValue
SecurityGroupIngress:
# RDPポート
- IpProtocol: tcp
FromPort: 3389
ToPort: 3389
CidrIp: !Ref ClientIp
# MoonlightのTCPポート
- IpProtocol: tcp
FromPort: 47984
ToPort: 47984
CidrIp: !Ref ClientIp
- IpProtocol: tcp
FromPort: 47989
ToPort: 47989
CidrIp: !Ref ClientIp
- IpProtocol: tcp
FromPort: 48010
ToPort: 48010
CidrIp: !Ref ClientIp
# MoonlightのUDPポート
- IpProtocol: udp
FromPort: 47998
ToPort: 48000
CidrIp: !Ref ClientIp
- IpProtocol: udp
FromPort: 48002
ToPort: 48002
CidrIp: !Ref ClientIp
- IpProtocol: udp
FromPort: 48010
ToPort: 48010
CidrIp: !Ref ClientIp
# 固定グローバルIP用 Elastic IP
ElasticIP:
Type: AWS::EC2::EIP
Properties:
Domain: vpc
# EC2インスタンス用のLaunchTemplate(スポットインスタンス設定)
MoonlightLaunchTemplate:
Type: AWS::EC2::LaunchTemplate
Properties:
LaunchTemplateName: MoonlightLaunchTemplate
LaunchTemplateData:
ImageId: !Ref AmiId
InstanceType: !Ref InstanceType
KeyName: xxxxx # EC2キーペア
SecurityGroupIds:
- !GetAtt InstanceSecurityGroup.GroupId
IamInstanceProfile:
Name: MoonlightInstanceProfile
BlockDeviceMappings:
# Cドライブ(OS用)
- DeviceName: /dev/sda1
Ebs:
VolumeSize: 100
VolumeType: gp3
DeleteOnTermination: true
VolumeInitializationRate: 100
InstanceMarketOptions:
MarketType: spot
SpotOptions:
SpotInstanceType: one-time
InstanceInterruptionBehavior: terminate
# EC2インスタンス(LaunchTemplateを使用)
MoonlightInstance:
Type: AWS::EC2::Instance
Properties:
LaunchTemplate:
LaunchTemplateId: !Ref MoonlightLaunchTemplate
Version: !GetAtt MoonlightLaunchTemplate.LatestVersionNumber
Tags:
- Key: Name
Value: Moonlight-Instance
# Elastic IP をインスタンスに関連付け
EipAssociation:
Type: AWS::EC2::EIPAssociation
Properties:
InstanceId: !Ref MoonlightInstance
AllocationId: !GetAtt ElasticIP.AllocationId
↓以降は構築の際に発生した色々な問題です。
Step 5: 停止時にスナップショット増殖にハマる
起動はうまくいきました。
次は「どうやって止めるか」です。
当初の停止フロー
最初は、停止時に次のようなことをしていました。
- Cドライブのスナップショットを作成
- Dドライブ(ゲームデータ)のスナップショットを作成
- CloudFormationスタックを削除(EC2も含めて全部削除)
これも Lambda を使って実行していたのですが…。
EBSのスナップショットは、変更量が多いと作成に結構時間がかかります。
- Lambdaがタイムアウトし、「失敗したからリトライするね!」とLambdaのリトライ設定により同じ処理を試みる
結果として、
- C・Dドライブのスナップショットが毎回無駄に3つずつ増える
という、お財布に優しくない現象が発生しました。
わたしのお財布を攻撃してきたのは、敵キャラではなく Lambda でした。
Step 6: 性能調査 〜CPU100%問題とGPUが働かない問題〜
起動・停止の仕組みができたので、次は性能のチューニングです。
g4dn.xlarge の CPU100%問題(→ g4dn.2xlarge へ引き上げ)
フルHD向けゲーム用として使っている g4dn.2xlarge は、当初 g4dn.xlarge を使っていました。
しかし、
- ゲーム中にCPUが100%張り付き
- GPU側に余力があるのに、CPUがボトルネックになる
という状況がありました。
なのでvCPUが2倍になる g4dn.2xlarge を使用すると良い感じの性能を発揮するようになりました。
g5.xlarge でGPUが使われない問題
一方、より解像度の高いゲーム用に g5.xlarge を使ったところ、
- ゲーム中でもGPU使用率がまったく上がらない
- Windows標準のディスプレイドライバが良くない動きをしている
という現象も起きました。
この問題は標準のディスプレイドライバを無効化すると、ようやくGPUがきちんと使われるようになりました。
Step 7: Dドライブのゲーム読み込みが異常に遅い
ディスク周りでも、こんな現象がありました。
- ゲームをDドライブに置くと、初回起動だけロードが異常に遅い
- 一度起動すると、同じインスタンスでは次回以降スムーズ
- しかしスナップショットから新しく立てたインスタンスではまた遅い
- ゲームによってはほとんど気にならないものもある
EBSの「ボリューム初期化レート」の調整
原因の一つとして考えたのが、EBSボリュームの初期化です。
Amazon EBS には「ボリューム初期化レート」を制御する機能があり、
これを 100 MiB/s に設定してみたところ、
- 初回起動時のロード時間が体感でかなりマシになった
- スナップショットから復元した直後でも、そこまで待たされない
という改善が見られました。
クラウドのディスクは、
「最初に一度“ならす”作業(初期化)」
することでアクセス速度を上げることができるようです。
Step 8: iPad がカクつく AWDL問題
クライアント側にも問題が発生しました。
Wi-Fiだとカクカク、有線だと快適
iPad から接続していると、
- Wi-Fi接続時には、1秒ごとに「プチッ」とコマ落ちするようなカクつき
- 有線LANやiPhoneの有線テザリング経由だと、かなり快適
という現象が起きました。
調べていくと、iOSやiPadOSの AWDL(AirDropなどに使われる仕組み)が、
- Wi-Fiを細かく別用途に使う
- そのタイミングでリアルタイムの映像伝送が影響を受ける
といった話が見つかり、
今回の現象ともだいぶ符号が合っていました。
iCloudサインアウトで改善するが…
一部の情報では、
- iCloudからサインアウトすると改善する
という話もあり、実際試してみると確かにカクつきは無くなりました。
ただ、
- 普段の生活で iCloud をバリバリ使っている身としては、
サインアウトしたまま運用するのは現実的ではない
ということで、
- 本気で遊びたいとき:有線テザリング or 物理的な有線接続
- Wi-Fiで軽く遊びたいとき:たまにカクつくのは仕様として割り切る
くらいに考えるようにしました。
問題を乗り越えて遊べるようになりました
そしてiPadからクラウドPCを起動してBluetoothコントローラーを接続したら準備完了!



料金について
最後に料金ですが、スポットインスタンスの価格は需給のバランスによって変わります。

ここ3ヶ月の平均だと1時間あたりは以下の通りです。
t3.xlarge:$0.1412 約 21.89 円
g4dn.2xlarge:$0.6709 約 104.00 円
g5.xlarge:$0.6192 約 95.98 円
※1ドル155円計算
実は100%CPU張り付き問題の際に g4dn.xlarge を g4dn.2xlarge に変更したことで
g5.xlarge の価格を超えてしまいました。
GPU(グラフィック)性能は g5.xlarge の方が高いため、ゲーム目的だと g4dn.2xlarge を使う意味は無くなってしまいました...
また、その他にAMI(スナップショット)の保管料が必要になります。
↓100GBのスナップショットを1ヶ月保管した場合は約5ドル(約800円)必要になります。

利用規約まわりについて、ゆるく触れておく
最後に、クラウドゲーミングとリモートデスクトップの利用規約まわりについて軽く触れておきます。
この構成はあくまで、
- 自分のAWSアカウント上で
- 自分専用インスタンスを
- 自分だけが利用する
という前提で作っています。
公開情報を眺める限り、このレベルの個人利用が
大きな問題になるとは考えにくい、という認識を持っています。
ただし、もし将来的に
- 友人・第三者にクラウドPCを貸し出す
- お金を取って「クラウドゲームPCサービス」を始める
といったサービス提供の形に進める場合は、
- Windows Server の RDS ライセンス
- 各ゲームタイトルの利用許諾(クラウド利用/レンタル禁止条項など)
など、しっかり確認すべきポイントが一気に増えます。
なのでこの記事はあくまで、
「クラウド好きが個人でやってみた、趣味の検証記録」
として読んでいただければと思います。
まとめ 〜クラウドにすべて置いてきたもの〜
こうして、自宅にあったPC達の役目はクラウドPCによってまかなえるようになりました。
クラウドにすべて置くことが出来ました。
(「すべて」は言いすぎでしたね、「ほとんど」に訂正してお詫び申し上げます)
そして残ったのは、
- iPad
- キーボード
- コントローラー
- そして月初に届くAWSの請求書
くらいです。
それにしても問題がいくつも出て解決するのは大変でしたが、
どこからでも iPad ひとつで「自分専用のクラウドゲームPC」を呼び出せる体験は、
かなり快適でした。
今後は、
- スナップショット運用の見直し
- さらにコストを抑える工夫
- DynamoDBでのログ&料金可視化
などを続けつつ、
「クラウドにすべてほとんど置いてきた」生活をもう少し楽しんでみようと思います。
と、この記事を書いている裏で MacBookPro M5 モデルを購入してしまい、もうすぐ届くことは内緒話です🤫
おしまい。







