こんにちは、近藤(りょう)です!
"Public" ではなく "Private" な環境で開発を行う場合に VPC など諸々の下準備(主に足回り)が必要でしたので 環境構築の 効率化重視 で「CFn(CloudFormation)を用いて AWS Cloud9 の環境をセットアップ」をしてみました。
AWS Cloud9 について
AWS Cloud9 は、ブラウザのみを使用してコードを記述、実行、デバッグできる無料のクラウドベースの統合開発環境 (IDE) です。IDE には、コードエディタ、デバッガー、ターミナルが含まれています。
AWS Cloud9 には、JavaScript、Python、PHP などの一般的なプログラム言語に不可欠なツールがあらかじめパッケージ化されているため、新しいプロジェクトを開始するためにファイルをインストールしたり、開発マシンを設定したりする必要はありません。
AWS Cloud9(Cloud IDE でコードを記述、実行、デバッグ)| AWS
Private な環境でのAWS Cloud9 利用について
AWS Cloud9 には SSH と SSM(AWS Systems Manager)2つのネットワーク接続方式が提供されていますが、Private な環境(Private Subnet上) に AWS Cloud9 を構築するので "SSM 接続方式" を選択する必要があります。
- 以下、Amazon VPC 要件 AWS Cloud9 の抜粋
- 環境が SSH 経由で EC2 インスタンスに直接アクセスしている場合、インスタンスはパブリックサブネットでのみ起動できます。
- Systems Manager を使って no-ingress Amazon EC2 インスタンスにアクセスしている場合、インスタンスはパブリックサブネットまたはプライベートサブネットに起動できます。
- プライベートサブネットを使用している場合は、パブリックサブネットで NAT ゲートウェイをホストして、サブネットのインスタンスによるインターネットとの通信を許可します。
「パブリックサブネットで NAT ゲートウェイをホストして、サブネットのインスタンスによるインターネットとの通信を許可します。」と記載がありますが
Systems Manager でプライベート EC2 インスタンスを管理できるようにVPCエンドポイントを利用すればできるようですね。
必要なVPCエンドポイント
- com.amazonaws.[region].ec2messages
- com.amazonaws.[region].ssm
- com.amazonaws.[region].ssmmessages
参考
AWS Systems Manager を使用して no-ingress EC2 インスタンスにアクセスする - AWS Cloud9
インターネットにアクセスせずにプライベート EC2 インスタンスを管理する | AWS re:Post
ただ、インターネットにつながっていないとそれはそれで開発効率は落ちそうです。
今回の構成
Private Subnet 上に AWS Cloud9 を配置して NAT Gateway 経由で外部(インターネット)への接続ができるような構成を構築します。

環境構築してみる
東京リージョンにAWS Cloud9を構築してみます。
CFn 実行
東京リージョンでCFnをぽちっとな。
※Parametersは各々修正お願いします。
AWSTemplateFormatVersion: '2010-09-09'
Description: Create a VPC with Public/Private Subnets, NAT Gateway, and Cloud9 IDE on Private Subnet using Session Manager
Parameters:
EnvironmentName:
Description: An environment name that is prefixed to resource names
Type: String
Default: myapp
VpcCIDR:
Description: Please enter the IP range (CIDR notation) for this VPC
Type: String
Default: 10.200.0.0/16
AvailabilityZoneName:
Description: Please enter the AvailabilityZoneName for Availability Zone
Type: String
Default: ap-northeast-1a
PublicSubnetCIDR:
Description: Please enter the IP range (CIDR notation) for the public subnet
Type: String
Default: 10.200.0.0/24
PrivateSubnetCIDR:
Description: Please enter the IP range (CIDR notation) for the private subnet
Type: String
Default: 10.200.1.0/24
Cloud9OwnerArn:
Type: String
Default: <Cloud9 OWNER ARN>
# Cloud9OwnerArnの部分はCloud9環境のオーナーにしたいIAMユーザー、ロールのARNを記載
# 別アカウントからスイッチロールした先のアカウントでCloud9を構築する場合はarn:aws:sts::スイッチ先アカウント番号:assumed-role/スイッチ先ロール名/セッション名(ユーザー名)
Metadata:
AWS::CloudFormation::Interface:
ParameterGroups:
-
Label:
default: "Basic Configuration"
Parameters:
- "EnvironmentName"
- "VpcCIDR"
- "AvailabilityZoneName"
- "PublicSubnetCIDR"
- "PrivateSubnetCIDR"
- "Cloud9OwnerArn"
Resources:
# ------------------------------------------------------------#
# VPC
# ------------------------------------------------------------#
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VpcCIDR
EnableDnsHostnames: true
EnableDnsSupport: true
InstanceTenancy: default
Tags:
- Key: Name
Value: !Sub ${EnvironmentName}-vpc
# ------------------------------------------------------------#
# PublicSubnet
# ------------------------------------------------------------#
PublicSubnet:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
AvailabilityZone: !Ref AvailabilityZoneName
CidrBlock: !Ref PublicSubnetCIDR
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: !Sub ${EnvironmentName}-public-subnet
# ------------------------------------------------------------#
# PrivateSubnet
# ------------------------------------------------------------#
PrivateSubnet:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
AvailabilityZone: !Ref AvailabilityZoneName
CidrBlock: !Ref PrivateSubnetCIDR
MapPublicIpOnLaunch: false
Tags:
- Key: Name
Value: !Sub ${EnvironmentName}-private-subnet
# ------------------------------------------------------------#
# InternetGateway and associate
# ------------------------------------------------------------#
InternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: !Sub ${EnvironmentName}-igw
InternetGatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref VPC
InternetGatewayId: !Ref InternetGateway
# ------------------------------------------------------------#
# Nat Gateway
# ------------------------------------------------------------#
NatGateway:
Type: AWS::EC2::NatGateway
Properties:
AllocationId: !GetAtt NatGatewayEIP.AllocationId
SubnetId: !Ref PublicSubnet
Tags:
- Key: Name
Value: !Sub ${EnvironmentName}-ngw
NatGatewayEIP:
Type: AWS::EC2::EIP
Properties:
Domain: vpc
# ------------------------------------------------------------#
# PublicSubnet Route Table
# ------------------------------------------------------------#
PublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub ${EnvironmentName}-public-route
DefaultPublicRoute:
Type: AWS::EC2::Route
DependsOn: InternetGatewayAttachment
Properties:
RouteTableId: !Ref PublicRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref InternetGateway
# ------------------------------------------------------------#
# PrivateSubnet Route Table
# ------------------------------------------------------------#
PrivateRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub ${EnvironmentName}-private-route
DefaultPrivateRoute:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref PrivateRouteTable
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId: !Ref NatGateway
# ------------------------------------------------------------#
# PublicSubnet Associate
# ------------------------------------------------------------#
PublicSubnetRouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PublicRouteTable
SubnetId: !Ref PublicSubnet
# ------------------------------------------------------------#
# PrivateSubnet Associate
# ------------------------------------------------------------#
PrivateSubnetRouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PrivateRouteTable
SubnetId: !Ref PrivateSubnet
# ------------------------------------------------------------#
# Cloud9
# ------------------------------------------------------------#
Cloud9Environment:
Type: AWS::Cloud9::EnvironmentEC2
Properties:
InstanceType: t2.micro
SubnetId: !Ref PrivateSubnet
AutomaticStopTimeMinutes: 30
ImageId: resolve:ssm:/aws/service/cloud9/amis/amazonlinux-2023-x86_64
Name: !Sub ${EnvironmentName}-cloud9
ConnectionType: CONNECT_SSM
OwnerArn: !Ref Cloud9OwnerArn
Outputs:
Cloud9EnvironmentId:
Description: The ID of the Cloud9 Environment
Value: !Ref Cloud9Environment
VPCId:
Description: The ID of the VPC
Value: !Ref VPC
PublicSubnetId:
Description: The ID of the Public Subnet
Value: !Ref PublicSubnet
PublicSubnetCIDR:
Description: The CIDR of the Public Subnet
Value: !Ref PublicSubnetCIDR
PrivateSubnetId:
Description: The ID of the Private Subnet
Value: !Ref PrivateSubnet
PrivateSubnetCIDR:
Description: The CIDR of the Private Subnet
Value: !Ref PrivateSubnetCIDR
NATGatewayId:
Description: The ID of the NAT Gateway
Value: !Ref NatGateway
NATGatewayEIP:
Description: The Elastic IP of the NAT Gateway
Value: !Ref NatGatewayEIP
Cloud9EnvironmentName:
Description: The Name of the Cloud9 Environment
Value: !GetAtt Cloud9Environment.Name
AWS Cloud9 の CFnの記載は「AWS::Cloud9::EnvironmentEC2」をご参照ください。
CFn 状態確認
CFnで作成するとマネージメントコンソールで AWS Cloud9 を作成した時と同じように AWS Cloud9用のCFn が動くみたいです。

ネットワーク 状態確認
CFnで作成した AWS Cloud9 のサブネットを確認します。

PrivateSubnet上に起動しているのが確認できます。(サブネット IDで検索)

リソースマップも確認してみる。(NATGW経由になっている)

AWS Cloud9 接続
AWS Cloud9を開いてみましょう。
対象の環境の「開く」を押下する。

AWS Cloud9へ接続できました。
※すぐ立ち上がらないこともありますのでその時はブラウザを更新してください

これでPrivate な環境でAWS Cloud9を作成することができました。
AWS Cloud9からNatGW経由でインターネットへ通信することもできます。
まとめ
Private な環境で開発をする必要があるといった場合に VPC などを手動で作成しておくのは手間がかかるのでCFnを利用した環境作成をご紹介させていただきました。
あまり、必要になることはないかもしれませんがどなたかの支えになれば幸いです。
近藤 諒都
(記事一覧)カスタマーサクセス部CS5課
夜行性ではありません。朝活派です。
趣味:お酒、旅行、バスケ、掃除、家庭用パン作り(ピザも)など
2025 Japan AWS All Certifications Engineers