Bootstrap AWS EC2 GPU instances for hybrid local-remote development
Project description
aws-bootstrap-g4dn
One command to go from zero to a fully configured GPU dev box on AWS โ with CUDA-matched PyTorch, Jupyter, SSH aliases, and a GPU benchmark ready to run.
aws-bootstrap launch # Spot g4dn.xlarge in ~3 minutes
ssh aws-gpu1 # You're in, venv activated, PyTorch works
โจ Key Features
| Feature | Details | |
|---|---|---|
| ๐ | One-command launch | Spot (default) or on-demand, with automatic fallback on capacity errors |
| ๐ | Auto SSH config | Adds aws-gpu1 alias to ~/.ssh/config โ no IP juggling. Cleaned up on terminate |
| ๐ | CUDA-aware PyTorch | Detects the installed CUDA toolkit (nvcc) and installs PyTorch from the matching wheel index โ no more torch.version.cuda mismatches |
| โ | PyTorch smoke test | Runs a quick torch.cuda matmul after setup to verify the GPU stack works end-to-end |
| ๐ | GPU benchmark included | CNN (MNIST) + Transformer benchmarks with FP16/FP32/BF16 precision and tqdm progress |
| ๐ | Jupyter ready | Lab server auto-starts as a systemd service on port 8888 โ just SSH tunnel and open |
| ๐ฅ๏ธ | status --gpu |
Shows CUDA toolkit version, driver max, GPU architecture, spot pricing, uptime, and estimated cost |
| ๐พ | EBS data volumes | Attach persistent storage at /data โ survives spot interruptions and termination, reattach to new instances |
| ๐๏ธ | Clean terminate | Stops instances, removes SSH aliases, cleans up EBS volumes (or preserves with --keep-ebs) |
| ๐ค | Agent Skill | Included Claude Code plugin lets LLM agents autonomously provision, manage, and tear down GPU instances |
๐ฏ Target Workflows
- Jupyter server-client โ Jupyter runs on the instance, connect from your local browser
- VSCode Remote SSH โ opens
~/workspacewith pre-configured CUDA debug/build tasks and an example.cufile - NVIDIA Nsight remote debugging โ GPU debugging over SSH
Requirements
- AWS profile configured with relevant permissions (profile name can be passed via
--profileor read fromAWS_PROFILEenv var) - AWS CLI v2 โ see here
- Python 3.12+ and uv
- An SSH key pair (see below)
Installation
From PyPI
pip install aws-bootstrap-g4dn
With uvx (no install needed)
uvx runs the CLI directly in a temporary environment โ no global install required:
uvx --from aws-bootstrap-g4dn aws-bootstrap launch
uvx --from aws-bootstrap-g4dn aws-bootstrap status
uvx --from aws-bootstrap-g4dn aws-bootstrap terminate
From source (development)
git clone https://github.com/promptromp/aws-bootstrap-g4dn.git
cd aws-bootstrap-g4dn
uv venv
uv sync
All methods install the aws-bootstrap CLI.
SSH Key Setup
The CLI expects an Ed25519 SSH public key at ~/.ssh/id_ed25519.pub by default. If you don't have one, generate it:
ssh-keygen -t ed25519
Accept the default path (~/.ssh/id_ed25519) and optionally set a passphrase. The key pair will be imported into AWS automatically on first launch.
To use a different key, pass --key-path:
aws-bootstrap launch --key-path ~/.ssh/my_other_key.pub
Usage
๐ Launching an Instance
# Show available commands
aws-bootstrap --help
# Dry run โ validates AMI lookup, key import, and security group without launching
aws-bootstrap launch --dry-run
# Launch a spot g4dn.xlarge (default)
aws-bootstrap launch
# Launch on-demand in a specific region with a custom instance type
aws-bootstrap launch --on-demand --instance-type g5.xlarge --region us-east-1
# Launch without running the remote setup script
aws-bootstrap launch --no-setup
# Use a specific Python version in the remote venv
aws-bootstrap launch --python-version 3.13
# Use a non-default SSH port
aws-bootstrap launch --ssh-port 2222
# Attach a persistent EBS data volume (96 GB gp3, mounted at /data)
aws-bootstrap launch --ebs-storage 96
# Reattach an existing EBS volume from a previous instance
aws-bootstrap launch --ebs-volume-id vol-0abc123def456
# Use a specific AWS profile
aws-bootstrap launch --profile my-aws-profile
After launch, the CLI:
- Creates/attaches EBS volume (if
--ebs-storageor--ebs-volume-idwas specified) - Adds an SSH alias (e.g.
aws-gpu1) to~/.ssh/config - Runs remote setup โ installs utilities, creates a Python venv, installs CUDA-matched PyTorch, sets up Jupyter
- Mounts EBS volume at
/data(if applicable โ formats new volumes, mounts existing ones as-is) - Runs a CUDA smoke test โ verifies
torch.cuda.is_available()and runs a quick GPU matmul - Prints connection commands โ SSH, Jupyter tunnel, GPU benchmark, and terminate
ssh aws-gpu1 # venv auto-activates on login
๐ง What Remote Setup Does
The setup script runs automatically on the instance after SSH becomes available:
| Step | What |
|---|---|
| GPU verify | Confirms nvidia-smi and nvcc are working |
| Utilities | Installs htop, tmux, tree, jq, ffmpeg |
| Python venv | Creates ~/venv with uv, auto-activates in ~/.bashrc. Use --python-version to pin a specific Python (e.g. 3.13) |
| CUDA-aware PyTorch | Detects CUDA toolkit version โ installs PyTorch from the matching cu{TAG} wheel index |
| CUDA smoke test | Runs torch.cuda.is_available() + GPU matmul to verify the stack |
| GPU benchmark | Copies gpu_benchmark.py to ~/gpu_benchmark.py |
| GPU smoke test notebook | Copies gpu_smoke_test.ipynb to ~/gpu_smoke_test.ipynb (open in JupyterLab) |
| Jupyter | Configures and starts JupyterLab as a systemd service on port 8888 |
| SSH keepalive | Configures server-side keepalive to prevent idle disconnects |
| VSCode workspace | Creates ~/workspace/.vscode/ with launch.json and tasks.json (auto-detected cuda-gdb path and GPU arch), plus an example saxpy.cu |
๐ GPU Benchmark
A GPU throughput benchmark is pre-installed at ~/gpu_benchmark.py on every instance:
# Run both CNN and Transformer benchmarks (default)
ssh aws-gpu1 'python ~/gpu_benchmark.py'
# CNN only, quick run
ssh aws-gpu1 'python ~/gpu_benchmark.py --mode cnn --benchmark-batches 20'
# Transformer only with custom batch size
ssh aws-gpu1 'python ~/gpu_benchmark.py --mode transformer --transformer-batch-size 16'
# Run CUDA diagnostics first (tests FP16/FP32 matmul, autocast, etc.)
ssh aws-gpu1 'python ~/gpu_benchmark.py --diagnose'
# Force FP32 precision (if FP16 has issues on your GPU)
ssh aws-gpu1 'python ~/gpu_benchmark.py --precision fp32'
Reports: iterations/sec, samples/sec, peak GPU memory, and avg batch time for each model.
๐ Jupyter (via SSH Tunnel)
ssh -NL 8888:localhost:8888 aws-gpu1
# Then open: http://localhost:8888
Or with explicit key/IP:
ssh -i ~/.ssh/id_ed25519 -NL 8888:localhost:8888 ubuntu@<public-ip>
A GPU smoke test notebook (~/gpu_smoke_test.ipynb) is pre-installed on every instance. Open it in JupyterLab to interactively verify the CUDA stack, run FP32/FP16 matmuls, train a small CNN on MNIST, and visualise training loss and GPU memory usage.
๐ฅ๏ธ VSCode Remote SSH
The remote setup creates a ~/workspace folder with pre-configured CUDA debug and build tasks:
~/workspace/
โโโ .vscode/
โ โโโ launch.json # CUDA debug configs (cuda-gdb path auto-detected)
โ โโโ tasks.json # nvcc build tasks (GPU arch auto-detected, e.g. sm_75)
โโโ saxpy.cu # Example CUDA source โ open and press F5 to debug
Connect directly from your terminal:
code --folder-uri vscode-remote://ssh-remote+aws-gpu1/home/ubuntu/workspace
Then install the Nsight VSCE extension on the remote when prompted. Open saxpy.cu, set a breakpoint, and press F5.
See Nsight remote profiling guide for more details on CUDA debugging and profiling workflows.
๐ค Structured Output
All commands support --output / -o for machine-readable output โ useful for scripting, piping to jq, or LLM tool-use:
# JSON output (pipe to jq)
aws-bootstrap -o json status
aws-bootstrap -o json status | jq '.instances[0].instance_id'
# YAML output
aws-bootstrap -o yaml status
# Table output
aws-bootstrap -o table status
# Works with all commands
aws-bootstrap -o json list instance-types | jq '.[].instance_type'
aws-bootstrap -o json launch --dry-run
aws-bootstrap -o json terminate --yes
aws-bootstrap -o json cleanup --dry-run
Supported formats: text (default, human-readable with color), json, yaml, table. Commands that require confirmation (terminate, cleanup) require --yes in structured output modes.
๐ Listing Resources
# List all g4dn instance types (default)
aws-bootstrap list instance-types
# List a different instance family
aws-bootstrap list instance-types --prefix p3
# List Deep Learning AMIs (default filter)
aws-bootstrap list amis
# List AMIs with a custom filter
aws-bootstrap list amis --filter "ubuntu/images/hvm-ssd-gp3/ubuntu-noble*"
# Use a specific region
aws-bootstrap list instance-types --region us-east-1
aws-bootstrap list amis --region us-east-1
๐ฅ๏ธ Managing Instances
# Show all aws-bootstrap instances (including shutting-down)
aws-bootstrap status
# Include GPU info (CUDA toolkit + driver version, GPU name, architecture) via SSH
aws-bootstrap status --gpu
# Hide connection commands (shown by default for each running instance)
aws-bootstrap status --no-instructions
# List instances in a specific region
aws-bootstrap status --region us-east-1
# Terminate all aws-bootstrap instances (with confirmation prompt)
aws-bootstrap terminate
# Terminate but preserve EBS data volumes for reuse
aws-bootstrap terminate --keep-ebs
# Terminate by SSH alias (resolved via ~/.ssh/config)
aws-bootstrap terminate aws-gpu1
# Terminate by instance ID
aws-bootstrap terminate i-abc123
# Mix aliases and instance IDs
aws-bootstrap terminate aws-gpu1 i-def456
# Skip confirmation prompt
aws-bootstrap terminate --yes
# Remove stale SSH config entries for terminated instances
aws-bootstrap cleanup
# Preview what would be removed without modifying config
aws-bootstrap cleanup --dry-run
# Also find and delete orphan EBS data volumes
aws-bootstrap cleanup --include-ebs
# Preview orphan volumes without deleting
aws-bootstrap cleanup --include-ebs --dry-run
# Skip confirmation prompt
aws-bootstrap cleanup --yes
status --gpu reports both the installed CUDA toolkit version (from nvcc) and the maximum CUDA version supported by the driver (from nvidia-smi), so you can see at a glance whether they match:
CUDA: 12.8 (driver supports up to 13.0)
SSH aliases are managed automatically โ they're created on launch, shown in status, and cleaned up on terminate. Aliases use sequential numbering (aws-gpu1, aws-gpu2, etc.) and never reuse numbers from previous instances. You can use aliases anywhere you'd use an instance ID, e.g. aws-bootstrap terminate aws-gpu1.
EBS Data Volumes
Attach persistent EBS storage to keep datasets and model checkpoints across instance lifecycles. Volumes are mounted at /data and persist independently of the instance.
# Create a new 96 GB gp3 volume, formatted and mounted at /data
aws-bootstrap launch --ebs-storage 96
# After terminating with --keep-ebs, reattach the same volume to a new instance
aws-bootstrap terminate --keep-ebs
# Output: Preserving EBS volume: vol-0abc123...
# Reattach with: aws-bootstrap launch --ebs-volume-id vol-0abc123...
aws-bootstrap launch --ebs-volume-id vol-0abc123def456
Key behaviors:
--ebs-storageand--ebs-volume-idare mutually exclusive- New volumes are formatted as ext4; existing volumes are mounted as-is
- Volumes are tagged for automatic discovery by
statusandterminate terminatedeletes data volumes by default; use--keep-ebsto preserve them- Orphan cleanup โ use
aws-bootstrap cleanup --include-ebsto find and delete orphan volumes (e.g. from spot interruptions or forgotten--keep-ebsvolumes). Use--dry-runto preview - Spot-safe โ data volumes survive spot interruptions. If AWS reclaims your instance, the volume detaches automatically and can be reattached to a new instance with
--ebs-volume-id - EBS volumes must be in the same availability zone as the instance
- Mount failures are non-fatal โ the instance remains usable
EC2 vCPU Quotas
AWS accounts have service quotas that limit how many vCPUs you can run per instance family. New or lightly-used accounts often have a default quota of 0 vCPUs for GPU instance families (G and VT), which will cause errors on launch:
- Spot:
MaxSpotInstanceCountExceeded - On-Demand:
VcpuLimitExceeded
Check your current quotas (g4dn.xlarge requires at least 4 vCPUs):
# Spot G/VT quota
aws service-quotas get-service-quota \
--service-code ec2 \
--quota-code L-3819A6DF \
--region us-west-2
# On-Demand G/VT quota
aws service-quotas get-service-quota \
--service-code ec2 \
--quota-code L-DB2BBE81 \
--region us-west-2
Request increases:
# Spot โ increase to 4 vCPUs
aws service-quotas request-service-quota-increase \
--service-code ec2 \
--quota-code L-3819A6DF \
--desired-value 4 \
--region us-west-2
# On-Demand โ increase to 4 vCPUs
aws service-quotas request-service-quota-increase \
--service-code ec2 \
--quota-code L-DB2BBE81 \
--desired-value 4 \
--region us-west-2
Quota codes may vary by region or account type. To list the actual codes in your region:
# List all G/VT-related quotas
aws service-quotas list-service-quotas \
--service-code ec2 \
--region us-west-2 \
--query "Quotas[?contains(QuotaName, 'G and VT')].[QuotaCode,QuotaName,Value]" \
--output table
Common quota codes:
L-3819A6DFโ All G and VT Spot Instance RequestsL-DB2BBE81โ Running On-Demand G and VT instances
Small increases (4-8 vCPUs) are typically auto-approved within minutes. You can also request increases via the Service Quotas console. While waiting, you can test the full launch/poll/SSH flow with a non-GPU instance type:
aws-bootstrap launch --instance-type t3.medium --ami-filter "ubuntu/images/hvm-ssd-gp3/ubuntu-noble-24.04-amd64-server-*"
Claude Code Plugin
A Claude Code plugin is included in the aws-bootstrap-skill/ directory, enabling LLM coding agents to autonomously provision and manage GPU instances.
Install from GitHub
# Add the marketplace (registers this repo as a plugin source)
/plugin marketplace add promptromp/aws-bootstrap-g4dn
# Install the plugin
/plugin install aws-bootstrap-skill@promptromp-aws-bootstrap-g4dn
Install locally (from repo checkout)
claude --plugin-dir ./aws-bootstrap-skill
See aws-bootstrap-skill/README.md for details.
Additional Resources
| Topic | Link |
|---|---|
| GPU instance pricing | instances.vantage.sh |
| Spot instance quotas | AWS docs |
| Deep Learning AMIs | AWS docs |
| Nsight remote GPU profiling | Guide โ Nsight Compute, Nsight Systems, and Nsight VSCE on EC2 |
Tutorials on setting up a CUDA environment on EC2 GPU instances:
- Provision an EC2 GPU Host on AWS (DoltHub, 2025)
- AWS EC2 Setup for GPU/CUDA Programming (TechForTalk, 2025)
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file aws_bootstrap_g4dn-0.8.1.tar.gz.
File metadata
- Download URL: aws_bootstrap_g4dn-0.8.1.tar.gz
- Upload date:
- Size: 105.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a821504b1fafd7da9d2bd2c368e513c4985c4ba6e556b65cc02de1458df97a8e
|
|
| MD5 |
12c8b8bd0bd13e9b9db2d11c6008a0f9
|
|
| BLAKE2b-256 |
5a91ed4daa6e48e806392fc53c3d57006196e47e06408ace1b0b9b4dda9439d9
|
Provenance
The following attestation bundles were made for aws_bootstrap_g4dn-0.8.1.tar.gz:
Publisher:
publish-to-pypi.yml on promptromp/aws-bootstrap-g4dn
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
aws_bootstrap_g4dn-0.8.1.tar.gz -
Subject digest:
a821504b1fafd7da9d2bd2c368e513c4985c4ba6e556b65cc02de1458df97a8e - Sigstore transparency entry: 919859306
- Sigstore integration time:
-
Permalink:
promptromp/aws-bootstrap-g4dn@4d972766e52c23f2e908ca62dfd12ab596ffeea7 -
Branch / Tag:
refs/tags/0.8.1 - Owner: https://github.com/promptromp
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-to-pypi.yml@4d972766e52c23f2e908ca62dfd12ab596ffeea7 -
Trigger Event:
push
-
Statement type:
File details
Details for the file aws_bootstrap_g4dn-0.8.1-py3-none-any.whl.
File metadata
- Download URL: aws_bootstrap_g4dn-0.8.1-py3-none-any.whl
- Upload date:
- Size: 68.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
04e560b90b88bf78df4f49914f4216337a31cd669ddf42a2c3a0a396cab34a1e
|
|
| MD5 |
4f0ae996b67fad36ef51d87c0ba70c22
|
|
| BLAKE2b-256 |
a7bdd4e08a1a03fc8395d246cb11b66fea1b4ba223599c62c280725c0eb2adb8
|
Provenance
The following attestation bundles were made for aws_bootstrap_g4dn-0.8.1-py3-none-any.whl:
Publisher:
publish-to-pypi.yml on promptromp/aws-bootstrap-g4dn
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
aws_bootstrap_g4dn-0.8.1-py3-none-any.whl -
Subject digest:
04e560b90b88bf78df4f49914f4216337a31cd669ddf42a2c3a0a396cab34a1e - Sigstore transparency entry: 919859309
- Sigstore integration time:
-
Permalink:
promptromp/aws-bootstrap-g4dn@4d972766e52c23f2e908ca62dfd12ab596ffeea7 -
Branch / Tag:
refs/tags/0.8.1 - Owner: https://github.com/promptromp
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-to-pypi.yml@4d972766e52c23f2e908ca62dfd12ab596ffeea7 -
Trigger Event:
push
-
Statement type: