I built a Claude Code environment usable only in a browser using EC2 + code-server + Bedrock

I built a Claude Code environment usable only in a browser using EC2 + code-server + Bedrock

I built a development environment on EC2 running code-server with Claude Code via Bedrock, accessible entirely through a browser. Authentication uses IAM roles, so users don't need API keys, making it well suited for training sessions and hands-on workshops.
2026.08.13

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 within it. This can be useful when you want to distribute temporary development environments for training sessions or hands-on workshops.

For Claude Code authentication, I use the IAM role attached to EC2 instead of an API key. Users can use Claude Code simply by opening a URL in their browser, without any authentication configuration.

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.

The code-server setup procedure was referenced from the following article.

https://dev.classmethod.jp/articles/ubuntu-2404-code-server-installation/

Configuration

Here is the configuration diagram of the environment we'll be creating.

Configuration diagram

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, and calls Bedrock using the permissions of the IAM role attached to 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 will be available for use immediately after submission.

You just need to do this from the console with your own IAM user, etc.
The role attached to EC2 does not need permissions to perform this operation (submitting the use case form).

https://docs.aws.amazon.com/bedrock/latest/userguide/model-access.html

Create an IAM Role

Prepare an IAM role to attach to EC2.
Since we want to avoid placing strong permissions on an EC2 that users will touch, we'll limit it to only the Bedrock model invocations that are needed.

Select EC2 as the trusted entity and create the 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 with this attached, 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 (12-digit number).

This policy allows Anthropic Claude models in general. This setting is convenient if you may want to switch models during use.

Note: If you want to restrict to a specific model

There may be reasons such as cost management where you want to fix which models can be called.
In that case, replace Resource as follows (example: limiting 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 for a single model is because cross-region inference profiles are being used.

The first is the ARN of the inference profile itself, which corresponds to the model ID specified by Claude Code.
The second and third are the ARNs of the foundation-models to which the inference profile distributes processing.
Since the jp. profile routes to Tokyo and Osaka, you also need to allow these two destination regions, or calls will fail.
Additionally, align 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

To access code-server from a browser, EC2 needs to be placed in a public subnet reachable from the internet. Since this isn't the main focus today, we'll create everything at once using the VPC → Create VPC → VPC and more wizard.

Item Setting
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 the VPC, public subnet, internet gateway, and route table all at once.
We won't create private subnets since they're not needed this time. NAT Gateway is also unnecessary (since it charges just for being running, please don't create one).

You can also reuse an existing VPC or the default VPC. In that case, make sure the subnet where EC2 will be placed is a public subnet (has a route to the internet gateway).

Launch an EC2 Instance

Create a Security Group

Prepare a security group before launching EC2 (e.g., code-server-sg).
For inbound, allow TCP port 50443 (where code-server listens) only from your own source IP.

Type Port Range Source
Custom TCP 50443 My IP

When you select My IP as the source, your global IP is automatically filled in as a /32 CIDR.
Since code-server authentication is password-only, avoid opening it to the entire internet (0.0.0.0/0).

We won't open TCP port 22 for SSH. We'll use Session Manager to log in to EC2.

Leave outbound settings as default (allow all). Outbound communication is required for installing code-server and Claude Code, Claude Code auto-updates, and calling the Bedrock API.

Launch the Instance

Launch an EC2 instance using the IAM role and security group you prepared.
Configure the following items.

Item Setting
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 Script below (under Advanced details)

While code-server itself is lightweight, considering that Claude Code and editor extensions will also run together, t3.micro (1GiB memory) or t3.small (2GiB) tend to run out of memory.
Therefore, we're using t3.medium with 2vCPU and 4GiB. We haven't verified operation on smaller sizes.

Storage has also been increased from the default 8GiB to 16GiB.
The OS, code-server, and Claude Code together use several GBs, so this is set with enough margin to account for repository clones and package installations. Adjust as needed for your use case along with the instance type.

User data is at the very bottom after opening Advanced details.

User data field in EC2 launch wizard

Paste the following script here (for Ubuntu 24.04).
This performs code-server and Claude Code installation, and 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 as the same user using sudo -u.

The Bedrock connection settings are written in the env section of ~/.claude/settings.json. While there's also a method of writing environment variables in .bashrc, that approach doesn't work for startup methods that don't go through bash.

Setting CLAUDE_CODE_USE_BEDROCK to 1 makes it use AWS credentials (the instance profile in this case) to call Bedrock instead of an API key. AWS_REGION is the region to call, and ANTHROPIC_MODEL specifies the model to use. Since the IAM policy broadly permits Anthropic models, you can change the model by rewriting 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 calls with a 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 in 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 public IPv4 address>:50443 in your browser (the public IPv4 address is shown in the instance details screen). Due to the self-signed certificate, you'll see a warning like the following.

Certificate warning screen

Click "Advanced" and a link will appear at the bottom saying "Proceed to <hostname> (unsafe)". Follow that link and log in with your password.

Open a terminal in code-server (from the menu: Terminal → New Terminal) and run the claude command. Since credentials are automatically obtained 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 also working.

Claude Code running in code-server terminal

If the startup header shows Sonnet 4.6 · Amazon Bedrock, it's running via Bedrock.
If you just 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 I'll list them as clues when things don't go well.

Symptom Cause and Solution
claude: command not found ~/.local/bin is not in PATH
Reopen the terminal or re-run the command to set the PATH
AccessDeniedException Check the Resource and account ID in the IAM policy, whether the Bedrock invocation policy is attached to the role, and also verify the use case form submission
on-demand throughput error The model ID is specified directly
Change to an inference profile ID with a prefix like jp.
Region-related error AWS_REGION and the profile region (jp. / apac. / us.) don't match
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 if the instance is "Running" and
whether AmazonSSMManagedInstanceCore is attached to the IAM role

Extensions Cannot Be Installed in This Configuration

code-server can install extensions from Open VSX (an extension marketplace) just like VS Code.
However, in this configuration, installation fails with an error like the following. This isn't 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 due to running code-server over HTTPS with a self-signed certificate.

Claude Code itself has not only a CLI version used from the terminal, but also an extension version that can be embedded as a side panel. This allows you to have conversations while viewing files and check changes in the editor, but for the same reason, it cannot be installed in this environment.

If you also want to use extensions (not just for Claude Code), you'll need to place CloudFront in front or set things up so that access is possible with a certificate trusted by the browser.


Automated Setup with CloudFormation

I have also prepared a CloudFormation template that can create all the configurations covered so far (VPC, Security Group, IAM Role, EC2) at once. They are separated by OS.

Ubuntu 24.04 Template (Full)
code-server-ubuntu.yaml
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)
code-server-al2023.yaml
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.
Verification steps are the same as when created via the console.

If you want to change the model being used, edit ANTHROPIC_MODEL in ~/.claude/settings.json within the template's user data.


Closing

I built an environment running Claude Code via Bedrock on code-server 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

https://dev.classmethod.jp/articles/ubuntu-2404-code-server-installation/

https://dev.classmethod.jp/articles/use-code-server-as-temporary-cloud9-alternative/

https://docs.aws.amazon.com/bedrock/latest/userguide/inference-profiles-support.html

https://docs.anthropic.com/en/docs/claude-code/amazon-bedrock


Claudeならクラスメソッドにお任せください

クラスメソッドは、Anthropic社とリセラー契約を締結しています。各種製品ガイドから、業種別の活用法、フェーズごとのお悩み解決などサービス支援ページにまとめております。まずはご覧いただき、お気軽にご相談ください。

サービス詳細を見る

Share this article

AWSのお困り事はクラスメソッドへ