
I built a Claude Code environment usable with just a browser using EC2 + code-server + Bedrock
This page has been translated by machine translation. View original
Hello, I'm Hayashi.
I tried setting up a web IDE (code-server) on EC2 that can be used with just a browser, and created an environment where Claude Code via Bedrock can be used inside it. This can be useful when you want to distribute temporary development environments for training sessions, hands-on workshops, and similar occasions.
For Claude Code authentication, instead of an API key, I use the IAM role attached to the EC2 instance. Users can use Claude Code without any authentication setup, simply by opening a URL in their browser.
The setup is done through the AWS console, but I've also included a CloudFormation template with the same configuration at the end of the article.
For the code-server setup procedure itself, I referenced this article.
Architecture
Here is the architecture diagram for the environment we'll be building.

We run code-server on EC2 placed in a public subnet and access it directly from a browser.
Claude Code is also installed on the same EC2 instance and calls Bedrock using the permissions of the IAM role attached to the EC2.
Enable Bedrock Model Access
When using Anthropic models for the first time, you need to submit a use case form.
Open Amazon Bedrock (Region: Tokyo) in the AWS console, select an Anthropic Claude model from Model catalog, and submit the use case form. It becomes available immediately after submission.
This can be done from the console using your own IAM user or similar.
The role attached to the EC2 does not need permission to perform this operation (submitting the use case form).
Create an IAM Role
Prepare an IAM role to attach to the EC2 instance.
Since we want to avoid placing strong permissions on the EC2 that users will touch, we limit it to only the Bedrock model invocations that are needed.
Select EC2 as the trusted entity and create a role (e.g., code-server-role).
There are two permissions to grant. Add the managed policy AmazonSSMManagedInstanceCore and the following Bedrock invocation policy as an inline policy.
AmazonSSMManagedInstanceCore is required for logging in via Session Manager,
and having it means you don't need to open the port for 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:*:<AccountID>:inference-profile/*.anthropic.*"
]
}
]
}
Replace <AccountID> with your own AWS account ID (a 12-digit number).
This policy allows all Anthropic Claude models broadly. This setting is convenient if you might switch models during use.
Note: If you want to restrict to a specific model
There may be cases where you want to fix which models can be called, for cost management or other reasons.
In that case, replace Resource as follows (example limited to jp.anthropic.claude-sonnet-4-6).
[
"arn:aws:bedrock:*:<AccountID>: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"
]
The reason three ARNs are needed to restrict to one model is because cross-region inference profiles are being used.
The first is the ARN of the inference profile itself, corresponding to the model ID specified by Claude Code.
The second and third are the ARNs of the foundation models that the inference profile routes processing to.
Since the jp. profile routes to Tokyo and Osaka, you must also allow these two regions as routing destinations, otherwise it cannot be called.
Also, align the ANTHROPIC_MODEL in ~/.claude/settings.json created in the user data described later to the same model ID.
If the model permitted in the IAM policy and the model actually called by Claude Code don't match, you'll get an AccessDeniedException.
Create a VPC
Since we're accessing code-server from a browser, the EC2 needs to be in a public subnet reachable from the internet. Since this isn't the main focus this time, we'll create everything together using the VPC → Create VPC → VPC and more wizard.
| Item | Value |
|---|---|
| Auto-generate name tag | code-server (example) |
| IPv4 CIDR block | 10.0.0.0/16 (default) |
| Number of Availability Zones | 1 |
| Number of public subnets | 1 |
| Number of private subnets | 0 |
| NAT gateway | None |
| VPC endpoints | None |
This creates a VPC, public subnet, internet gateway, and route table all at once.
We don't create private subnets since they're not used this time. A NAT gateway is also unnecessary (it incurs charges just by being running, so please don't create one).
You may also reuse an existing VPC or the default VPC. In that case, confirm that the subnet where you place the EC2 is a public subnet (has a route to an internet gateway).
Launch an EC2 Instance
Create a Security Group
Prepare a security group before launching the EC2 (e.g., code-server-sg).
For inbound, allow TCP port 50443, which code-server listens on, only from your own source IP.
| Type | Port Range | Source |
|---|---|---|
| Custom TCP | 50443 | My IP |
Selecting My IP as the source will automatically populate your global IP as a /32 CIDR.
Since code-server authentication is password-only, avoid opening it to the entire internet (0.0.0.0/0).
We do not open TCP port 22 for SSH. We use Session Manager to log into the EC2.
Leave the outbound settings at their defaults (allow all). Outbound communication is required for installing code-server and Claude Code, Claude Code's automatic updates, and calling the Bedrock API.
Launch the Instance
Launch the EC2 instance using the IAM role and security group you prepared.
Configure the following items.
| Item | Value |
|---|---|
| Name | code-server (example) |
| AMI | Ubuntu Server 24.04 LTS |
| Instance type | t3.medium |
| Key pair | Proceed without a key pair (not needed since we use Session Manager) |
| Network | code-server-vpc and its public subnet,enable auto-assign public IP |
| Security group | code-server-sg (select existing security group) |
| Storage | 16GiB, gp3 |
| IAM instance profile | code-server-role (under Advanced details) |
| User data | The script below (under Advanced details) |
While code-server itself is lightweight, t3.micro (1GiB memory) or t3.small (2GiB) tend to have insufficient memory when Claude Code and editor extensions are also running together.
That's why we're using t3.medium with 2 vCPUs and 4GiB. We have not verified operation on smaller sizes.
Storage has also been increased from the default 8GiB to 16GiB.
The OS, code-server, and Claude Code use several GB, so this provides some room allowing for repository cloning and package installations. Adjust along with the instance type according to your use case.
User data is at the very bottom after opening Advanced details.

Paste the following script here (for Ubuntu 24.04).
This handles installation of code-server and Claude Code, as well as Bedrock connection configuration, at startup.
#!/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'
For Amazon Linux 2023
Select Amazon Linux 2023 AMI for the AMI.
Use the following script for user data.
The differences are the package manager (apt→dnf), default user (ubuntu→ec2-user), and package format (.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'
Notes on User Data
Since code-server runs as the default user for each OS, Claude Code is also installed for the same user using sudo -u.
The Bedrock connection configuration is written in env in ~/.claude/settings.json. While writing environment variables in .bashrc is another approach, they won't be loaded for launches that don't go through bash.
Setting CLAUDE_CODE_USE_BEDROCK to 1 makes it call Bedrock using AWS credentials (in this case, the instance profile) instead of an API key. AWS_REGION specifies the target region for calls, and ANTHROPIC_MODEL specifies the model to use. Since the IAM policy broadly allows Anthropic models, if you want to change the model, rewrite ANTHROPIC_MODEL.
For ANTHROPIC_MODEL, specify a cross-region inference profile ID with a prefix like jp.. Relatively new models like Claude Sonnet 4.6 don't support on-demand invocation with the direct model ID without a prefix, and you'll get an on-demand throughput not supported error.
Verification
First, check the code-server password that was auto-generated by the user data.
Select the instance in the EC2 console and log in via Connect → Session Manager tab → Connect.
# For Ubuntu
sudo cat /home/ubuntu/.config/code-server/config.yaml | grep password:
# For Amazon Linux 2023
sudo cat /home/ec2-user/.config/code-server/config.yaml | grep password:
Access https://<instance's public IPv4 address>:50443 in your browser (the public IPv4 address is shown in the instance details screen). Because of the self-signed certificate, a warning like the following will appear.

Click "Advanced" and a link at the bottom saying "Proceed to <hostname> (unsafe)" will appear, proceed from there and log in with the password.
Open a terminal in code-server (from the menu: Terminal → New Terminal) and run the claude command. Since credentials are automatically retrieved via the instance profile, if Claude Code launches without setting an API key, you've succeeded.
Try sending an actual message, and if a response comes back from the specified model, the Bedrock integration is working.

If the startup header shows Sonnet 4.6 · Amazon Bedrock, it is running via Bedrock.
If you only want to check the authentication status, you can also use the claude auth status command.
Common Errors and Solutions
These basically won't occur if you follow the steps correctly, but here they are as clues for when things don't go as expected.
| Symptom | Cause and Solution |
|---|---|
claude: command not found |
~/.local/bin is not in PATHReopen the terminal or re-run the command to add PATH |
AccessDeniedException |
Check the Resource and account ID in the IAM policy, whether the Bedrock invocation policy is attached to the role, and also check that the use case form has been submitted |
| on-demand throughput error | The model ID is specified directly Change to an inference profile ID with a prefix like jp. |
| Region-related error | Mismatch between AWS_REGION and the profile's region (jp. / apac. / us.)Align them to the same region |
| User data didn't run | Log in via Session Manager and check the log with sudo cat /var/log/cloud-init-output.log |
| Cannot log in via Session Manager | Check whether the instance is in "running" state and whether AmazonSSMManagedInstanceCore is attached to the IAM role |
Extensions Cannot Be Installed in This Configuration
code-server, like VS Code, can install extensions from Open VSX (an extension marketplace).
However, in this configuration, installation fails with an error like the following. This is not limited to Claude Code extensions; it happens with all extensions installed from Open VSX.
IDE: ✘ Error installing VS Code extension: Command failed with ERR_STREAM_PREMATURE_CLOSE
I believe this is the effect of running code-server over HTTPS with a self-signed certificate.
Claude Code itself also has an extension version that can be embedded as a side panel, in addition to the CLI version used in the terminal. While it allows you to chat while viewing files and check changes in the editor, it cannot be installed in this environment for the same reason.
If you also want to use extensions (not just for Claude Code), you'll need to place CloudFront in front or make it accessible with a certificate trusted by the browser.
Automated Setup with CloudFormation
I've also prepared a CloudFormation template that can create all the configurations so far (VPC, security group, IAM role, EC2) at once. They are separated by OS.
Ubuntu 24.04 Template Full Text
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 Template Full Text
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
Specify your access source IP in AllowedIP and deploy.
aws cloudformation create-stack --stack-name temp-code-server \
--template-body file://./code-server-ubuntu.yaml \
--parameters "ParameterKey=AllowedIP,ParameterValue=<your access source IP>/32" \
--capabilities CAPABILITY_NAMED_IAM
For the Amazon Linux 2023 version, change --template-body to code-server-al2023.yaml.
The operation verification is the same as when created from the console.
If you want to change the model being used, rewrite ANTHROPIC_MODEL in ~/.claude/settings.json within the template's user data.
Finally
I built an environment with Claude Code via Bedrock on code-server running on EC2, using the AWS console.
Authentication is handled by the IAM role attached to the EC2 instance, so there is no need to distribute API keys to users. The permissions granted to the role can also be limited to only Bedrock model invocations.
Please give it a try if you cannot install Claude Code on your local machine, or if you simply want to try it out easily.
I hope this article is helpful to someone. Thank you for reading to the end!
References
