
ブラウザだけで使えるClaude Code環境をEC2 + code-server + Bedrockで作ってみた
こんにちは、林です。
EC2上にブラウザだけで使えるWeb IDE(code-server)を立てて、その中でBedrock経由のClaude Codeを使える環境を作ってみました。研修やハンズオンなど、一時的な開発環境を配りたいときに使えます。
Claude Codeの認証には、APIキーではなくEC2に付けたIAMロールを使います。利用者はブラウザでURLを開くだけで、認証設定なしにClaude Codeを使えます。
構築はAWSコンソールから進めますが、同じ構成のCloudFormationテンプレートも記事の最後に載せています。
code-server自体の構築手順は、こちらの記事を参考にさせていただきました。
構成
今回作る環境の構成図です。

パブリックサブネットに置いたEC2でcode-serverを動かし、ブラウザから直接アクセスします。
Claude Codeも同じEC2上にインストールし、EC2に付けたIAMロールの権限でBedrockを呼び出します。
Bedrockのモデルアクセスを有効化する
Anthropicのモデルを初めて使うときは、ユースケースフォームの提出が必要です。
AWSコンソールで Amazon Bedrock(リージョン: 東京)を開き、Model catalog からAnthropicのClaudeモデルを選んで、ユースケースフォームを送信します。送信後はすぐに使えるようになります。
これは自分のIAMユーザーなどでコンソールから実施すればOKです。
EC2に付けるロールには、この操作(ユースケースフォームの提出)を実施する権限は必要ありません。
IAMロールを作成する
EC2に付与するIAMロールを用意します。
利用者が触るEC2に強い権限を載せるのは避けたいので、必要なBedrockのモデル呼び出しだけに絞ります。
信頼されたエンティティに EC2 を選んでロールを作成します(例: code-server-role)。
付与する権限は2つです。マネージドポリシーの AmazonSSMManagedInstanceCore と、下記のBedrockを呼び出す用のポリシーをインラインポリシーとして追加します。
AmazonSSMManagedInstanceCore はSession Manager経由でログインするために必要なもので、
これを付けておけばSSH用のポートを開けなくて済みます。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "BedrockInvokeAnthropicModels",
"Effect": "Allow",
"Action": [
"bedrock:InvokeModel",
"bedrock:InvokeModelWithResponseStream"
],
"Resource": [
"arn:aws:bedrock:*::foundation-model/anthropic.*",
"arn:aws:bedrock:*:<アカウントID>:inference-profile/*.anthropic.*"
]
}
]
}
<アカウントID> は自分のAWSアカウントID(12桁の数字)に置き換えてください。
このポリシーはAnthropic Claude系のモデル全般を許可しています。利用中にモデルを切り替える可能性がある場合はこの設定が楽です。
補足: 使うモデルを特定のものに絞りたい場合
コスト管理などの理由で、呼び出せるモデルを固定したいこともあります。
その場合は Resource を次のように差し替えます(例として jp.anthropic.claude-sonnet-4-6 に限定)。
[
"arn:aws:bedrock:*:<アカウントID>:inference-profile/jp.anthropic.claude-sonnet-4-6",
"arn:aws:bedrock:ap-northeast-1::foundation-model/anthropic.claude-sonnet-4-6",
"arn:aws:bedrock:ap-northeast-3::foundation-model/anthropic.claude-sonnet-4-6"
]
1つのモデルに絞るのにARNが3つ必要なのは、クロスリージョン推論プロファイルを使っているためです。
1つ目はその推論プロファイル自体のARNで、Claude Codeが指定するモデルIDに対応します。
2つ目と3つ目は、推論プロファイルが処理を振り分ける先のfoundation-modelのARNです。
jp. プロファイルは東京・大阪にルーティングされるため、振り分け先となるこの2リージョン分も許可しないと呼び出せません。
あわせて、後述のユーザーデータで作成する ~/.claude/settings.json の ANTHROPIC_MODEL も、同じモデルIDに揃えてください。
IAMポリシーで許可したモデルと、Claude Codeが実際に呼び出すモデルが食い違うと AccessDeniedException になります。
VPCを作成する
code-serverにブラウザからアクセスするため、EC2はインターネットから到達できるパブリックサブネットに置きます。ここは今回の本題ではないので、VPC → VPCを作成 → VPC など のウィザードでまとめて作ります。
| 項目 | 設定値 |
|---|---|
| 名前タグの自動生成 | code-server(例) |
| IPv4 CIDR ブロック | 10.0.0.0/16(デフォルトのまま) |
| アベイラビリティーゾーンの数 | 1 |
| パブリックサブネットの数 | 1 |
| プライベートサブネットの数 | 0 |
| NATゲートウェイ | なし |
| VPCエンドポイント | なし |
これでVPC・パブリックサブネット・インターネットゲートウェイ・ルートテーブルが一度に作成されます。
プライベートサブネットは今回使わないので作りません。NATゲートウェイも不要です(起動しているだけで課金されるため、作らないようにしてください)。
既存のVPCやデフォルトVPCを流用してもかまいません。その場合は、EC2を置くサブネットがパブリックサブネットであること(インターネットゲートウェイへのルートを持つこと)を確認してください。
EC2インスタンスを起動する
セキュリティグループを作成する
EC2を起動する前にセキュリティグループを用意します(例: code-server-sg)。
インバウンドは、code-serverが待ち受けるTCP 50443番を、自分のアクセス元IPからのみ許可します。
| タイプ | ポート範囲 | ソース |
|---|---|---|
| カスタムTCP | 50443 | マイIP |
ソースに マイIP を選ぶと、自分のグローバルIPが /32 のCIDRで自動入力されます。
code-serverの認証はパスワードのみなので、インターネット全体(0.0.0.0/0)に開けるのは避けましょう。
SSH用のTCP 22番は開けません。EC2へのログインには、Session Managerを利用します。
アウトバウンドはデフォルト設定(すべて許可)のままにします。code-serverとClaude Codeのインストール、Claude Codeの自動更新、Bedrock APIの呼び出しで、外向きの通信が必要になるためです。
インスタンスを起動する
用意したIAMロールとセキュリティグループを使って、EC2インスタンスを起動します。
設定するのは次の項目です。
| 項目 | 設定値 |
|---|---|
| 名前 | code-server(例) |
| AMI | Ubuntu Server 24.04 LTS |
| インスタンスタイプ | t3.medium |
| キーペア | キーペアなしで続行(Session Managerで入るため不要) |
| ネットワーク | code-server-vpc とそのパブリックサブネット、パブリックIPの自動割り当てを有効化 |
| セキュリティグループ | code-server-sg(既存のセキュリティグループを選択) |
| ストレージ | 16GiB・gp3 |
| IAMインスタンスプロファイル | code-server-role(高度な詳細内) |
| ユーザーデータ | 下記のスクリプト(高度な詳細内) |
code-server自体は軽量ですが、Claude Codeやエディタの拡張機能もあわせて動くことを考えると、t3.micro(メモリ1GiB)やt3.small(2GiB)ではメモリが不足しがちです。
そのため2vCPU・4GiBのt3.mediumにしています。より小さいサイズでの動作確認はしていません。
ストレージもデフォルトの8GiBから16GiBに増やしています。
OSとcode-server、Claude Codeで数GBを使うため、リポジトリのcloneやパッケージのインストールを見込んで、ある程度余裕を持たせた値です。インスタンスタイプとあわせて、用途に応じて調整してください。
ユーザーデータは 高度な詳細 を開いた先の、いちばん下にあります。

ここに次のスクリプトを貼り付けます(Ubuntu 24.04の場合)。
code-serverとClaude Codeのインストール、Bedrock接続設定までを起動時に行います。
#!/bin/bash
set -eux
# Install code-server
apt update
apt install -y jq curl openssl
CODER_VERSION=$(curl -s https://api.github.com/repos/coder/code-server/releases/latest | jq -r .tag_name | sed 's/v//')
curl -fOL "https://github.com/coder/code-server/releases/download/v${CODER_VERSION}/code-server_${CODER_VERSION}_amd64.deb"
apt install -y ./code-server_${CODER_VERSION}_amd64.deb
rm -f code-server_${CODER_VERSION}_amd64.deb
mkdir -p /home/ubuntu/.config/code-server/
cat > /home/ubuntu/.config/code-server/config.yaml << EOF
bind-addr: 0.0.0.0:50443
auth: password
password: $(openssl rand -hex 16)
cert: true
EOF
chown -R ubuntu:ubuntu /home/ubuntu/.config
systemctl enable --now code-server@ubuntu
# Install Claude Code
sudo -u ubuntu bash -c 'curl -fsSL https://claude.ai/install.sh | bash'
mkdir -p /home/ubuntu/.claude
cat > /home/ubuntu/.claude/settings.json << 'EOF'
{
"env": {
"CLAUDE_CODE_USE_BEDROCK": "1",
"AWS_REGION": "ap-northeast-1",
"ANTHROPIC_MODEL": "jp.anthropic.claude-sonnet-4-6"
}
}
EOF
chown -R ubuntu:ubuntu /home/ubuntu/.claude
# Add PATH
sudo -u ubuntu bash -c 'grep -q ".local/bin" /home/ubuntu/.bashrc || echo "export PATH=\"$HOME/.local/bin:\$PATH\"" >> /home/ubuntu/.bashrc'
Amazon Linux 2023の場合
AMIは Amazon Linux 2023 AMI を選択します。
ユーザーデータは次のスクリプトを使ってください。
違いは、パッケージ管理(apt→dnf)、既定ユーザー(ubuntu→ec2-user)、パッケージ形式(.deb→.rpm)です。
#!/bin/bash
set -eux
# Install code-server
dnf install -y jq openssl
CODER_VERSION=$(curl -s https://api.github.com/repos/coder/code-server/releases/latest | jq -r .tag_name | sed 's/v//')
curl -fOL "https://github.com/coder/code-server/releases/download/v${CODER_VERSION}/code-server-${CODER_VERSION}-amd64.rpm"
dnf install -y ./code-server-${CODER_VERSION}-amd64.rpm
rm -f code-server-${CODER_VERSION}-amd64.rpm
mkdir -p /home/ec2-user/.config/code-server/
cat > /home/ec2-user/.config/code-server/config.yaml << EOF
bind-addr: 0.0.0.0:50443
auth: password
password: $(openssl rand -hex 16)
cert: true
EOF
chown -R ec2-user:ec2-user /home/ec2-user/.config
systemctl enable --now code-server@ec2-user
# Install Claude Code
sudo -u ec2-user bash -c 'curl -fsSL https://claude.ai/install.sh | bash'
mkdir -p /home/ec2-user/.claude
cat > /home/ec2-user/.claude/settings.json << 'EOF'
{
"env": {
"CLAUDE_CODE_USE_BEDROCK": "1",
"AWS_REGION": "ap-northeast-1",
"ANTHROPIC_MODEL": "jp.anthropic.claude-sonnet-4-6"
}
}
EOF
chown -R ec2-user:ec2-user /home/ec2-user/.claude
# Add PATH
sudo -u ec2-user bash -c 'grep -q ".local/bin" /home/ec2-user/.bashrc || echo "export PATH=\"$HOME/.local/bin:\$PATH\"" >> /home/ec2-user/.bashrc'
ユーザーデータの補足
code-serverは各OSの既定ユーザー動作するため、Claude Codeも sudo -u で同じユーザーにインストールしています。
Bedrockの接続設定は ~/.claude/settings.json の env に書いています。.bashrc に環境変数を書く方法もありますが、bashを経由しない起動では読み込まれないためです。
CLAUDE_CODE_USE_BEDROCK を 1 にすると、APIキーではなくAWSの認証情報(今回はインスタンスプロファイル)でBedrockを呼びます。AWS_REGION が呼び出し先リージョン、ANTHROPIC_MODEL が使うモデルの指定です。IAMポリシーはAnthropic系を広く許可しているので、モデルを変えたいときは ANTHROPIC_MODEL を書き換えてください。
ANTHROPIC_MODEL には、jp. のようなプレフィックスが付いたクロスリージョン推論プロファイルIDを指定してください。Claude Sonnet 4.6のような比較的新しいモデルは、プレフィックスなしの直接のモデルIDだとオンデマンド呼び出しに対応しておらず、on-demand throughput 非対応 のエラーになります。
動作確認
まず、ユーザーデータで自動生成されたcode-serverのパスワードを確認します。
EC2コンソールでインスタンスを選択し、接続 → Session Manager タブ → 接続でログインしてください。
# Ubuntuの場合
sudo cat /home/ubuntu/.config/code-server/config.yaml | grep password:
# Amazon Linux 2023の場合
sudo cat /home/ec2-user/.config/code-server/config.yaml | grep password:
ブラウザで https://<インスタンスのパブリックIPv4アドレス>:50443 にアクセスします(パブリックIPv4アドレスはインスタンスの詳細画面に表示されます)。自己署名証明書のため、次のような警告が出ます。

「詳細設定」を押すと最下部に「<ホスト名> にアクセスする(安全ではありません)」というリンクが出るので、そこから進み、パスワードでログインしてください。
code-serverでターミナルを開き(メニューの Terminal → New Terminal)、claude コマンドを実行します。インスタンスプロファイル経由で認証情報が自動取得されるので、APIキーを設定しなくてもClaude Codeが立ち上がれば成功です。
実際にメッセージを送ってみて、指定したモデルから応答が返ってくればBedrock連携までOKです。

起動時のヘッダーに Sonnet 4.6 · Amazon Bedrock と出ていれば、Bedrock経由で動いています。
認証まわりの状態だけを確認したい場合は claude auth status コマンドも使えます。
よくあるエラーと対処
手順どおりに進めれば基本的には発生しませんが、うまくいかないときの手がかりとして挙げておきます。
| 症状 | 原因と対処 |
|---|---|
claude: command not found |
PATHに ~/.local/bin が無いターミナルを開き直すか、PATHを通すコマンドを再実行する |
AccessDeniedException |
IAMポリシーのResourceやアカウントIDを確認する、Bedrock呼び出し用ポリシーがロールに付いているかどうか、ユースケースフォームの提出も確認する |
| on-demand throughput エラー | モデルIDが直接指定になっているjp. などのプレフィックス付き推論プロファイルIDに変更する |
| リージョン系エラー | AWS_REGION とプロファイルの地域(jp. / apac. / us.)が不一致同じ地域にそろえる |
| ユーザーデータが動いていない | Session Managerでログインし、sudo cat /var/log/cloud-init-output.log でログを確認する |
| Session Managerでログインできない | インスタンスが「実行中」か、 IAMロールに AmazonSSMManagedInstanceCore が付いているかを確認する |
この構成では拡張機能をインストールできない
code-serverは、VS Codeと同じようにOpen VSX(拡張機能のマーケットプレイス)から拡張機能を入れられます。
ところが今回の構成では、次のようなエラーでインストールに失敗します。これはClaude Code用の拡張に限った話ではなく、Open VSXから入れる拡張機能全般に起きます。
IDE: ✘ Error installing VS Code extension: Command failed with ERR_STREAM_PREMATURE_CLOSE
これはcode-serverを自己署名証明書のHTTPSで動かしている影響とみています。
Claude Code自身にも、ターミナルで使うCLI版のほかに、サイドパネルとして組み込める拡張機能版があります。ファイルを見ながら会話したり、変更箇所をエディタ上で確認したりできるものですが、この環境では同じ理由でインストールできません。
拡張機能(Claude Code用に限らず)も使いたい場合は、CloudFrontを前段に置くなどして、ブラウザに信頼される証明書でアクセスできるようにする必要があります。
CloudFormationで自動構築する
ここまでの構成(VPC・セキュリティグループ・IAMロール・EC2)を一度に作成できるCloudFormationテンプレートも用意しました。OSごとに分けています。
Ubuntu 24.04版 テンプレート全文
AWSTemplateFormatVersion: 2010-09-09
Description: code-server + Claude Code (Amazon Bedrock) on Ubuntu 24.04
Metadata:
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: Set basic information.
Parameters:
- SystemName
- Label:
default: Set your EC2 instance settings.
Parameters:
- InstanceType
- AllowedIP
- AMIID
Parameters:
SystemName:
Description: "Prefix of each resource name."
Type: String
Default: "code-server"
InstanceType:
Description: "EC2 instance type."
Type: String
Default: "t3.medium"
AllowedIP:
Description: "Your access source IP in CIDR notation (e.g. 203.0.113.10/32)."
Type: String
AMIID:
Description: "Ubuntu 24.04 AMI ID."
Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
Default: /aws/service/canonical/ubuntu/server/24.04/stable/current/amd64/hvm/ebs-gp3/ami-id
Resources:
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.0.0.0/16
EnableDnsHostnames: true
EnableDnsSupport: true
Tags:
- Key: Name
Value: !Sub "${SystemName}-vpc"
InternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: !Sub "${SystemName}-igw"
AttachGateway:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref VPC
InternetGatewayId: !Ref InternetGateway
PublicSubnet:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: !Select [0, !GetAZs ""]
VpcId: !Ref VPC
CidrBlock: 10.0.1.0/24
Tags:
- Key: Name
Value: !Sub "${SystemName}-public-subnet"
PublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub "${SystemName}-public-rtb"
PublicRoute:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref PublicRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref InternetGateway
PublicRouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PublicRouteTable
SubnetId: !Ref PublicSubnet
CodeServerSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupName: !Sub "${SystemName}-sg"
GroupDescription: "Security group for code-server (HTTPS on 50443)"
VpcId: !Ref VPC
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 50443
ToPort: 50443
CidrIp: !Ref AllowedIP
Tags:
- Key: Name
Value: !Sub "${SystemName}-sg"
CodeServerRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub
- "${SystemName}-role-${Suffix}"
- Suffix: !Select [4, !Split ["-", !Select [2, !Split ["/", !Ref "AWS::StackId"]]]]
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Principal:
Service:
- "ec2.amazonaws.com"
Action:
- "sts:AssumeRole"
ManagedPolicyArns:
- "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
Policies:
- PolicyName: "BedrockInvokeAnthropicModels"
PolicyDocument:
Version: "2012-10-17"
Statement:
- Sid: "BedrockInvokeAnthropicModels"
Effect: "Allow"
Action:
- "bedrock:InvokeModel"
- "bedrock:InvokeModelWithResponseStream"
Resource:
- "arn:aws:bedrock:*::foundation-model/anthropic.*"
- !Sub "arn:aws:bedrock:*:${AWS::AccountId}:inference-profile/*.anthropic.*"
CodeServerInstanceProfile:
Type: AWS::IAM::InstanceProfile
Properties:
Roles:
- !Ref CodeServerRole
CodeServerEC2:
Type: AWS::EC2::Instance
Properties:
ImageId: !Ref AMIID
InstanceType: !Ref InstanceType
BlockDeviceMappings:
- DeviceName: /dev/sda1
Ebs:
Encrypted: true
VolumeSize: 16
VolumeType: gp3
DeleteOnTermination: true
NetworkInterfaces:
- AssociatePublicIpAddress: true
DeviceIndex: "0"
SubnetId: !Ref PublicSubnet
GroupSet:
- !Ref CodeServerSecurityGroup
IamInstanceProfile: !Ref CodeServerInstanceProfile
Tags:
- Key: Name
Value: !Ref SystemName
UserData:
Fn::Base64: |
#!/bin/bash
set -eux
# Install code-server
apt update
apt install -y jq curl openssl
CODER_VERSION=$(curl -s https://api.github.com/repos/coder/code-server/releases/latest | jq -r .tag_name | sed 's/v//')
curl -fOL "https://github.com/coder/code-server/releases/download/v${CODER_VERSION}/code-server_${CODER_VERSION}_amd64.deb"
apt install -y ./code-server_${CODER_VERSION}_amd64.deb
rm -f code-server_${CODER_VERSION}_amd64.deb
mkdir -p /home/ubuntu/.config/code-server/
cat > /home/ubuntu/.config/code-server/config.yaml << EOF
bind-addr: 0.0.0.0:50443
auth: password
password: $(openssl rand -hex 16)
cert: true
EOF
chown -R ubuntu:ubuntu /home/ubuntu/.config
systemctl enable --now code-server@ubuntu
# Install Claude Code
sudo -u ubuntu bash -c 'curl -fsSL https://claude.ai/install.sh | bash'
mkdir -p /home/ubuntu/.claude
cat > /home/ubuntu/.claude/settings.json << 'EOF'
{
"env": {
"CLAUDE_CODE_USE_BEDROCK": "1",
"AWS_REGION": "ap-northeast-1",
"ANTHROPIC_MODEL": "jp.anthropic.claude-sonnet-4-6"
}
}
EOF
chown -R ubuntu:ubuntu /home/ubuntu/.claude
# Add PATH
sudo -u ubuntu bash -c 'grep -q ".local/bin" /home/ubuntu/.bashrc || echo "export PATH=\"$HOME/.local/bin:\$PATH\"" >> /home/ubuntu/.bashrc'
Outputs:
PublicIP:
Description: "code-server public IP. Access it at https://<PublicIP>:50443"
Value: !GetAtt CodeServerEC2.PublicIp
Amazon Linux 2023版 テンプレート全文
AWSTemplateFormatVersion: 2010-09-09
Description: code-server + Claude Code (Amazon Bedrock) on Amazon Linux 2023
Metadata:
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: Set basic information.
Parameters:
- SystemName
- Label:
default: Set your EC2 instance settings.
Parameters:
- InstanceType
- AllowedIP
- AMIID
Parameters:
SystemName:
Description: "Prefix of each resource name."
Type: String
Default: "code-server"
InstanceType:
Description: "EC2 instance type."
Type: String
Default: "t3.medium"
AllowedIP:
Description: "Your access source IP in CIDR notation (e.g. 203.0.113.10/32)."
Type: String
AMIID:
Description: "Amazon Linux 2023 AMI ID."
Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
Default: /aws/service/ami-amazon-linux-latest/al2023-ami-kernel-6.1-x86_64
Resources:
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.0.0.0/16
EnableDnsHostnames: true
EnableDnsSupport: true
Tags:
- Key: Name
Value: !Sub "${SystemName}-vpc"
InternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: !Sub "${SystemName}-igw"
AttachGateway:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref VPC
InternetGatewayId: !Ref InternetGateway
PublicSubnet:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: !Select [0, !GetAZs ""]
VpcId: !Ref VPC
CidrBlock: 10.0.1.0/24
Tags:
- Key: Name
Value: !Sub "${SystemName}-public-subnet"
PublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub "${SystemName}-public-rtb"
PublicRoute:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref PublicRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref InternetGateway
PublicRouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PublicRouteTable
SubnetId: !Ref PublicSubnet
CodeServerSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupName: !Sub "${SystemName}-sg"
GroupDescription: "Security group for code-server (HTTPS on 50443)"
VpcId: !Ref VPC
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 50443
ToPort: 50443
CidrIp: !Ref AllowedIP
Tags:
- Key: Name
Value: !Sub "${SystemName}-sg"
CodeServerRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub
- "${SystemName}-role-${Suffix}"
- Suffix: !Select [4, !Split ["-", !Select [2, !Split ["/", !Ref "AWS::StackId"]]]]
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Principal:
Service:
- "ec2.amazonaws.com"
Action:
- "sts:AssumeRole"
ManagedPolicyArns:
- "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
Policies:
- PolicyName: "BedrockInvokeAnthropicModels"
PolicyDocument:
Version: "2012-10-17"
Statement:
- Sid: "BedrockInvokeAnthropicModels"
Effect: "Allow"
Action:
- "bedrock:InvokeModel"
- "bedrock:InvokeModelWithResponseStream"
Resource:
- "arn:aws:bedrock:*::foundation-model/anthropic.*"
- !Sub "arn:aws:bedrock:*:${AWS::AccountId}:inference-profile/*.anthropic.*"
CodeServerInstanceProfile:
Type: AWS::IAM::InstanceProfile
Properties:
Roles:
- !Ref CodeServerRole
CodeServerEC2:
Type: AWS::EC2::Instance
Properties:
ImageId: !Ref AMIID
InstanceType: !Ref InstanceType
BlockDeviceMappings:
- DeviceName: /dev/xvda
Ebs:
Encrypted: true
VolumeSize: 16
VolumeType: gp3
DeleteOnTermination: true
NetworkInterfaces:
- AssociatePublicIpAddress: true
DeviceIndex: "0"
SubnetId: !Ref PublicSubnet
GroupSet:
- !Ref CodeServerSecurityGroup
IamInstanceProfile: !Ref CodeServerInstanceProfile
Tags:
- Key: Name
Value: !Ref SystemName
UserData:
Fn::Base64: |
#!/bin/bash
set -eux
# Install code-server
dnf install -y jq openssl
CODER_VERSION=$(curl -s https://api.github.com/repos/coder/code-server/releases/latest | jq -r .tag_name | sed 's/v//')
curl -fOL "https://github.com/coder/code-server/releases/download/v${CODER_VERSION}/code-server-${CODER_VERSION}-amd64.rpm"
dnf install -y ./code-server-${CODER_VERSION}-amd64.rpm
rm -f code-server-${CODER_VERSION}-amd64.rpm
mkdir -p /home/ec2-user/.config/code-server/
cat > /home/ec2-user/.config/code-server/config.yaml << EOF
bind-addr: 0.0.0.0:50443
auth: password
password: $(openssl rand -hex 16)
cert: true
EOF
chown -R ec2-user:ec2-user /home/ec2-user/.config
systemctl enable --now code-server@ec2-user
# Install Claude Code
sudo -u ec2-user bash -c 'curl -fsSL https://claude.ai/install.sh | bash'
mkdir -p /home/ec2-user/.claude
cat > /home/ec2-user/.claude/settings.json << 'EOF'
{
"env": {
"CLAUDE_CODE_USE_BEDROCK": "1",
"AWS_REGION": "ap-northeast-1",
"ANTHROPIC_MODEL": "jp.anthropic.claude-sonnet-4-6"
}
}
EOF
chown -R ec2-user:ec2-user /home/ec2-user/.claude
# Add PATH
sudo -u ec2-user bash -c 'grep -q ".local/bin" /home/ec2-user/.bashrc || echo "export PATH=\"$HOME/.local/bin:\$PATH\"" >> /home/ec2-user/.bashrc'
Outputs:
PublicIP:
Description: "code-server public IP. Access it at https://<PublicIP>:50443"
Value: !GetAtt CodeServerEC2.PublicIp
AllowedIP に自分のアクセス元IPを指定してデプロイします。
aws cloudformation create-stack --stack-name temp-code-server \
--template-body file://./code-server-ubuntu.yaml \
--parameters "ParameterKey=AllowedIP,ParameterValue=<自分のアクセス元IP>/32" \
--capabilities CAPABILITY_NAMED_IAM
Amazon Linux 2023版は --template-body を code-server-al2023.yaml に変えてください。
動作確認はコンソールで作った場合と同じです。
使うモデルを変えたい場合は、テンプレートのユーザーデータ内、~/.claude/settings.json の ANTHROPIC_MODEL を書き換えてください。
さいごに
EC2上のcode-serverにBedrock経由のClaude Codeを載せた環境を、AWSコンソールから構築しました。
認証はEC2に付けたIAMロールで行うので、利用者にAPIキーを配る必要がありません。ロールに与える権限も、Bedrockのモデル呼び出しだけに絞れます。
手元の端末にClaude Codeをインストールできない場合や、まずは手軽に触ってみたい場合に試してみてください。
この記事がどなたかの参考になれば幸いです。最後までご覧いただきありがとうございました!
参考








