A CDK stack that deploys a remote development environment accessible via browser, featuring:
- code-server (VS Code in the browser)
- nginx reverse proxy with HTTPS
- Let's Encrypt automatic SSL certificate
- Route 53 DNS (optional, for automatic DNS management)
- Claude Code CLI pre-installed
+-------------+ HTTPS/443 +-----------------------------+
| Browser | ---------------> | EC2 Instance |
+-------------+ | +-- nginx (reverse proxy) |
| +-- code-server (VS Code) |
+-------------+ SSH/22 | +-- Claude Code CLI |
| SSH Client | ---------------> | |
+-------------+ +-----------------------------+
|
v
+-----------------------------+
| Route 53 (optional) |
| dev.yourdomain.com -> IP |
+-----------------------------+
claude-server/
├── bin/claude-server.ts # CDK app entry point
├── lib/claude-server-stack.ts # Main CDK stack
├── config/
│ ├── config.example.ts # Configuration template (committed)
│ └── config.ts # Actual config (gitignored)
├── scripts/
│ └── init.sh # EC2 user-data script
└── test/ # CDK tests
- AWS Account with CLI configured (
aws configure) - Node.js 18+ installed
- AWS CDK installed globally:
npm install -g aws-cdk - EC2 Key Pair created in your target region
- Route 53 Hosted Zone (optional, for automatic DNS management)
npm installcp config/config.example.ts config/config.tsEdit config/config.ts with your values:
| Variable | Description | Example |
|---|---|---|
region |
AWS region for deployment | us-east-1 |
domain |
Subdomain for code-server | dev.mysite.com |
ssmPasswordParameterName |
SSM Parameter name for password | /claude-server/code-server-password |
email |
Email for Let's Encrypt | me@email.com |
keyPairName |
EC2 Key Pair name | my-key-pair |
additionalSshPublicKeys |
Additional SSH public keys (optional) | ['ssh-rsa AAAA...'] |
instanceType |
EC2 instance type (optional) | t4g.small |
volumeSize |
EBS volume size in GB (optional) | 30 |
useElasticIp |
Use static Elastic IP (optional) | true |
hostedZoneId |
Route 53 Hosted Zone ID (optional) | Z0123456789ABC |
enableSshPasswordAuth |
Enable SSH password login (optional) | false |
Note: If useElasticIp is true and hostedZoneId is provided, DNS is managed automatically by CDK. Otherwise, create the DNS A record manually.
aws ssm put-parameter \
--name "/claude-server/code-server-password" \
--type SecureString \
--value "your-strong-password" \
--region us-east-1cdk bootstrap aws://YOUR_ACCOUNT_ID/YOUR_REGIONcdk deployCDK automatically validates that the SSM parameter exists before deploying.
- Open
https://dev.yourdomain.com - Enter your code-server password
- Open terminal (Ctrl+
) and runclaude`
- Host:
dev.yourdomain.com - User:
ec2-user - Auth: Your EC2 key pair private key
- Run
claudein terminal
| Resource | Cost/month |
|---|---|
| EC2 t4g.small | ~$12 |
| Public IP | ~$3.60 |
| EBS 30GB GP3 | ~$2.40 |
| Route 53 | ~$0.50 |
| Total | ~$18.5/month |
To reduce costs:
- Use
t4g.micro(~$8/month total) - Stop instance when not in use
| Command | Description |
|---|---|
cdk synth |
Generate CloudFormation template |
cdk deploy |
Deploy (validates SSM parameter first) |
cdk diff |
Show changes |
cdk destroy |
Delete the stack |
# Via SSH
ssh ec2-user@dev.yourdomain.com
sudo cat /var/log/user-data.log
# Via AWS Console
# EC2 > Instance > Actions > Monitor > Get System Logsudo systemctl restart code-server@ec2-usersudo certbot renew- SSH is open to all IPs (0.0.0.0/0). Consider restricting to your IP for better security.
- code-server is protected by password authentication.
- Password is stored securely in AWS SSM Parameter Store as SecureString (encrypted with KMS).
- SSM Session Manager is enabled as a backup access method.
- Never commit
config/config.tsto version control.
By default, SSH uses key-based authentication only. To enable password login, set enableSshPasswordAuth: true in your config. This uses the same password as code-server (from SSM Parameter Store).
MIT