A command-line tool for managing DigitalOcean droplets with automated setup, SSH configuration, and lifecycle management.
- 🚀 Quick droplet creation with cloud-init automation
- 🔑 Automatic SSH configuration - just run
ssh dropkit.<droplet-name> - 🔐 Tailscale VPN - secure access via Tailscale (enabled by default)
- 👤 User management - automatically creates your user account on droplets
- 🏷️ Smart tagging - organizes droplets by owner for easy filtering
- 🔒 Security-first - SSH key validation, confirmation prompts for destructive operations
- 📊 Rich CLI - beautiful tables, progress indicators, and helpful error messages
- 🔄 Complete lifecycle - create, list, resize, destroy droplets with ease
- 💤 Hibernate/Wake - snapshot and destroy to save costs, restore later with one command
- Python 3.11+
- DigitalOcean account with an API token (create one here)
- SSH key pair (usually
~/.ssh/id_ed25519.pubor~/.ssh/id_rsa.pub) - uv package manager (install instructions)
- Tailscale (optional but recommended) - install from tailscale.com/download
# HTTPS or SSH depending on your GitHub setup
uv tool install git+https://github.com/trailofbits/dropkit.git
uv tool install git+ssh://git@github.com/trailofbits/dropkit.git
# Upgrade
uv tool upgrade dropkitRun the initialization wizard:
dropkit initThis will validate your DigitalOcean API token, detect SSH keys, register them with DigitalOcean, and let you choose defaults (type ? for help to see available options).
# Interactive mode - prompts for name, region, size, image (type ? for help)
dropkit create
# Or specify the name and use defaults
dropkit create my-first-droplet
# Assign to a specific project (by name or ID)
dropkit create my-droplet --project "My Project"
# Create without Tailscale VPN
dropkit create my-droplet --no-tailscaleThe tool will:
- Create the droplet and wait for it to become active
- Add SSH configuration automatically
- Wait for cloud-init to complete
- Tailscale setup (enabled by default):
- Display an auth URL for you to authenticate in your browser
- Update SSH config with your Tailscale IP
- Lock down the firewall to only allow Tailscale traffic
ssh dropkit.my-first-dropletYour user account is already set up with your SSH keys.
Usage: dropkit [OPTIONS] COMMAND [ARGS]...
Manage DigitalOcean droplets
Commands:
init Initialize dropkit configuration.
create Create a new DigitalOcean droplet with cloud-init configuration.
list List droplets and hibernated snapshots tagged with owner:<username>.
config-ssh Configure SSH for an existing droplet.
info Show detailed information about a droplet.
rename Rename a droplet (requires confirmation).
destroy Destroy a droplet or hibernated snapshot (DESTRUCTIVE).
resize Resize a droplet (causes downtime - requires power off).
on Power on a droplet.
off Power off a droplet (requires confirmation).
hibernate Hibernate a droplet (snapshot and destroy to save costs).
wake Wake a hibernated droplet (restore from snapshot).
enable-tailscale Enable Tailscale VPN on an existing droplet.
list-ssh-keys List SSH keys registered via dropkit.
add-ssh-key Add or import an SSH public key to DigitalOcean.
delete-ssh-key Delete an SSH key registered via dropkit.
version Show the version of dropkit.
Use dropkit <command> --help for detailed help on any command.
Configuration files are stored in ~/.config/dropkit/:
config.yaml- Main configuration (API token, defaults, SSH keys)cloud-init.yaml- Cloud-init template (customizable)
All droplets are automatically tagged with:
owner:<username>- Your DigitalOcean account username (derived from email)firewall- For security group identification
- Set default project during
dropkit init(type?to see available projects) - Override per-droplet using
--project <name>withdropkit create - Specify by name or UUID; tab completion available
All SSH config entries use the prefix dropkit.<droplet-name>:
- Connect with:
ssh dropkit.my-droplet
Enable tab completion for droplet names in your shell:
Zsh (recommended):
dropkit --install-completion zshBash:
dropkit --install-completion bashAfter installation, restart your shell. Tab completion dynamically fetches your droplets from DigitalOcean:
dropkit info <TAB> # Shows your droplets
dropkit destroy <TAB> # Shows your droplets
dropkit resize <TAB> # Shows your droplets
dropkit on <TAB> # Shows your droplets
dropkit off <TAB> # Shows your dropletsDigitalOcean charges for stopped droplets at the full hourly rate. To avoid this, use hibernate/wake:
# Hibernate: snapshot the droplet and destroy it (stops billing)
dropkit hibernate my-droplet
# Wake: restore the droplet from the snapshot
dropkit wake my-droplet
# Delete a hibernated snapshot without restoring
dropkit destroy my-dropletHow it works:
hibernatepowers off the droplet, creates a snapshot (dropkit-<name>), then destroys the dropletwakecreates a new droplet from the snapshot with the same region and size- Snapshots are tagged with
owner:<username>andsize:<size-slug>for tracking - After waking, you're prompted to delete the snapshot (default: yes)
Note: Snapshots are billed at $0.06/GB/month, which is typically much cheaper than keeping a droplet running.
Edit ~/.config/dropkit/cloud-init.yaml to customize user setup, package installation, firewall rules, and shell configuration. The template uses Jinja2 syntax with variables {{ username }} and {{ ssh_keys }}.
Initialize the configuration:
dropkit initCheck cloud-init status manually:
ssh dropkit.my-droplet 'sudo cloud-init status'
ssh dropkit.my-droplet 'sudo cat /var/log/cloud-init.log'Use --verbose flag to see detailed output:
dropkit create my-droplet --verboseThe droplet might belong to someone else. List your droplets:
dropkit listuv run pytest # All tests
uv run pytest -v # Verbose output
uv run pytest -k "pattern" # Filter by nameThe E2E lifecycle test creates a real droplet, verifies SSH connectivity,
and destroys it. Registered as a prek manual stage hook — run before
pushing changes that affect core workflows.
./tests/e2e/test_lifecycle.sh # Run directly
prek run --stage manual # Run via prekRequires a valid dropkit config (~/.config/dropkit/config.yaml) with a
DigitalOcean API token. The test randomly selects hardcoded defaults for its
region, size, and image (currently Ubuntu 24.04 or 26.04 LTS), so user config
defaults don't affect test behavior.
Optional environment variable overrides: DROPLET_NAME, DROPLET_REGION,
DROPLET_SIZE, DROPLET_IMAGE, E2E_SSH_TIMEOUT.
- CLI Framework: Typer - Modern CLI framework
- UI/Display: Rich - Terminal formatting
- API Client: requests - HTTP library
- Configuration: Pydantic - Data validation
- Templating: Jinja2 - Cloud-init templates
- Package Manager: uv - Fast Python package manager
- Code Quality: Ruff (linter/formatter) + ty (type checker)
- Go to DigitalOcean API Tokens
- Click Generate New Token with name "dropkit-cli"
- Select Custom Scopes (recommended) or Full Access (simpler)
- For custom scopes, enable the 23 scopes listed below
account:read, actions:read, droplet:create, droplet:read, droplet:update, droplet:delete, image:create, image:read, image:update, image:delete, project:read, project:update, regions:read, sizes:read, snapshot:read, snapshot:delete, ssh_key:create, ssh_key:read, ssh_key:update, ssh_key:delete, tag:read, tag:create, vpc:read
| Feature | Required Scopes |
|---|---|
| Initialize config | account:read, regions:read, sizes:read, image:read, ssh_key:read, ssh_key:create, project:read |
| Create droplets | droplet:create, project:update, actions:read, tag:create |
| List droplets | droplet:read, snapshot:read, tag:read |
| Show droplet info | droplet:read |
| Destroy droplets | droplet:delete, snapshot:delete |
| Rename droplets | droplet:update |
| Resize droplets | droplet:update, sizes:read, actions:read |
| Power on/off | droplet:update, actions:read |
| Hibernate | droplet:update, droplet:delete, snapshot:create, actions:read, tag:create |
| Wake | droplet:create, snapshot:read, snapshot:delete |
| Manage SSH keys | ssh_key:read, ssh_key:create, ssh_key:update, ssh_key:delete |
For more information, see the DigitalOcean API Token Scopes documentation.