{"id":13502834,"url":"https://github.com/petems/tugboat","last_synced_at":"2025-05-16T07:04:01.308Z","repository":{"id":8010525,"uuid":"9418724","full_name":"petems/tugboat","owner":"petems","description":"A command line tool for interacting with your DigitalOcean droplets.","archived":false,"fork":false,"pushed_at":"2018-03-11T19:09:27.000Z","size":709,"stargazers_count":1449,"open_issues_count":12,"forks_count":89,"subscribers_count":30,"default_branch":"master","last_synced_at":"2025-05-04T22:16:31.121Z","etag":null,"topics":["digitalocean","droplet","ruby","tugboat"],"latest_commit_sha":null,"homepage":null,"language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/petems.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2013-04-13T19:14:45.000Z","updated_at":"2025-01-23T23:54:42.000Z","dependencies_parsed_at":"2022-09-01T11:52:08.769Z","dependency_job_id":null,"html_url":"https://github.com/petems/tugboat","commit_stats":null,"previous_names":["pearkes/tugboat"],"tags_count":27,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/petems%2Ftugboat","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/petems%2Ftugboat/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/petems%2Ftugboat/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/petems%2Ftugboat/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/petems","download_url":"https://codeload.github.com/petems/tugboat/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254485053,"owners_count":22078767,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["digitalocean","droplet","ruby","tugboat"],"created_at":"2024-07-31T22:02:26.426Z","updated_at":"2025-05-16T07:04:01.286Z","avatar_url":"https://github.com/petems.png","language":"Ruby","funding_links":[],"categories":["Ruby","Happy Exploring 🤘"],"sub_categories":[],"readme":"# Tugboat\n[![Build Status](https://travis-ci.org/petems/tugboat.svg?branch=master)](https://travis-ci.org/petems/tugboat)\n[![Coverage Status](https://coveralls.io/repos/github/petems/tugboat/badge.svg?branch=master)](https://coveralls.io/github/petems/tugboat?branch=master)\n\nA command line tool for interacting with your [DigitalOcean](https://www.digitalocean.com/) droplets.\n\n## History\n\nWhen Tugboat was created, DigitalOcean was an extremely new cloud provider. They'd only released their public beta back in [2012](https://whoapi.com/blog/1497/fast-growing-digitalocean-is-fueled-by-customer-love/), and their new SSD backed machines only premiered in early [2013](https://techcrunch.com/2013/01/15/techstars-graduate-digitalocean-switches-to-ssd-for-its-5-per-month-vps-to-take-on-linode-and-rackspace/).\n\nTugboat started out life around that time, [back in April 2013](https://github.com/pearkes/tugboat/commit/f0fbc1f438cce81c286f0e60014dc4393ac95cb6). Back then, there were no official libraries for DigitalOcean, and the 1.0 API was a bit unstable and occasionally flakey.\n\nSince then, DigitalOcean has expanded rapidly and has started offering official libraries.\n\nThey now have an offically maintained command-line client called [doctl](https://github.com/digitalocean/doctl).\n\nSome people have asked, **where does that leave Tugboat?**\n\nIf you want the bleeding edge of new features and official support from DigitalOcean engineers, **Doctl is the way to go**. However, **as long as there is one other user out there who likes Tugboat and it's workflow, I will try my darndest to maintain this project, investigate bugs, implement new features and merge pull-requests.**\n\n## Installation\n\n    gem install tugboat\n\nPlease note that Tugboat version 0.2.0 and up requires Ruby 1.9 or higher.\n\n## Configuration\n\nRun the configuration utility, `tugboat authorize`. You can grab your keys\n[here](https://cloud.digitalocean.com/api_access).\n\n    $ tugboat authorize\n    Enter your client key: foo\n    Enter your API key: bar\n    Enter your SSH key path (optional, defaults to ~/.ssh/id_rsa):\n    Enter your SSH user (optional, defaults to jack):\n    Enter your SSH port number (optional, defaults to 22):\n\n    To retrieve region, image, size and key ID's, you can use the corresponding tugboat command, such as `tugboat images`.\n    Defaults can be changed at any time in your ~/.tugboat configuration file.\n\n    Enter your default region ID (optional, defaults to 1 (New York)):\n    Enter your default image ID (optional, defaults to 350076 (Ubuntu 13.04 x64)):\n    Enter your default size ID (optional, defaults to 66 (512MB)):\n    Enter your default ssh key IDs (optional, defaults to '', comma separated string):\n\n    Authentication with DigitalOcean was successful!\n\nThis will create a .tugboat file in your home folder (eg. ~/.tugboat).\n\nTugboat will look for a .tugboat config file first in the current directory you're running it in, then will look for one in the home directory.\n\nAn example of a `.tugboat` file:\n\n```yaml\n---\nauthentication:\n  access_token: f8sazukxeh729ggxh9gjavvzw5cabdpq95txpzhz6ep6jvtquxztfkf2chyejcsg5\nssh:\n  ssh_user: root\n  ssh_key_path: \"~/.ssh/id_rsa\"\n  ssh_port: '22'\ndefaults:\n  region: nyc2\n  image: ubuntu-14-04-x64\n  size: 512mb\n  ssh_key: ['1234','5678']\n  private_networking: 'false'\n  backups_enabled: 'false'\n  ip6: 'false'\n```\n\n\n\n## Usage\n\n### Retrieve a list of your droplets\n\n    $ tugboat droplets\n    pearkes-web-001 (ip: 30.30.30.1, status: active, region: nyc2, id: 13231511)\n    pearkes-admin-001 (ip: 30.30.30.3, status: active, region: nyc2, id: 13231512)\n    pearkes-api-001 (ip: 30.30.30.5, status: active, region: nyc2, id: 13231513)\n\nIf you wish to use the droplet listing as part of scripting or munging output, you can use the `--porcelain`:\n\n    $ tugboat droplets --attribute=ip4\n    pearkes-web-001,30.30.30.1\n    pearkes-admin-001,30.30.30.3\n    pearkes-api-001,30.30.30.5\n\nOr `--attribute` parameter:\n\n    $ tugboat droplets --porcelain\n    name pearkes-web-001\n    id 13231515\n    status active\n    ip4 330.30.30.1\n    region lon1\n    image 6918990\n    size 1gb\n    backups_active false\n\n    name pearkes-admin-001\n    id 13231513\n    status active\n    ip4 30.30.30.3\n    region lon1\n    image 6918990\n    size 1gb\n    backups_active false\n\n    name pearkes-web-001\n    id 13231514\n    status active\n    ip4 30.30.30.5\n    region lon1\n    image 6918990\n    size 1gb\n    backups_active true\n\n\n### Fuzzy name matching\n\nYou can pass a unique fragment of a droplets name for interactions\nthroughout `tugboat`.\n\n    $ tugboat restart admin\n    Droplet fuzzy name provided. Finding droplet ID...done, 13231512 (pearkes-admin-001)\n    Queuing restart for 13231512 (pearkes-admin-001)...done\n\ntugboat handles multiple matches as well:\n\n    $ tugboat restart pearkes\n    Droplet fuzzy name provided. Finding droplet ID...Multiple droplets found.\n\n    0) pearkes-web-001  (13231511)\n    1) pearkes-admin-001 (13231512)\n    2) pearkes-api-001 (13231513)\n\n    Please choose a droplet: [\"0\", \"1\", \"2\"] 0\n    Queuing restart for 13231511 (pearkes-web-001)...done\n\n### SSH into a droplet\n\n*You can configure an SSH username and key path in `tugboat authorize`,\nor by changing your `~/.tugboat`.*\n\nThis lets you ssh into a droplet by providing it's name, or a partial\nmatch.\n\n    $ tugboat ssh admin\n    Droplet fuzzy name provided. Finding droplet ID...done, 13231512 (pearkes-admin-001)\n    Executing SSH (pearkes-admin-001)...\n    Welcome to Ubuntu 12.10 (GNU/Linux 3.5.0-17-generic x86_64)\n    pearkes@pearkes-admin-001:~#\n\n### SCP files to droplet\n\n*You can configure an SSH username and key path in `tugboat authorize`,\nor by changing your `~/.tugboat`.*\n\nThis lets you scp a file into a droplet by providing it's name, or a partial\nmatch.\n\n    $ tugboat scp test-scp /tmp/foo /tmp/bar\n    Droplet fuzzy name provided. Finding droplet ID...done, 72025053 (test-scp)\n    Executing SCP on Droplet (test-scp)...\n    Attempting SCP with `scp -i /Users/petems/.ssh/digital_ocean /tmp/foo root@132.61.164.113:/tmp/bar`\n    foo\n                                                  100%    0     0.0KB/s   00:00\n\n### Create a droplet\n\n    $ tugboat create pearkes-www-002 -s 512mb -i ubuntu-12-04-x64 -r nyc2 -k 11251\n    Queueing creation of droplet 'pearkes-www-002'...done\n\n### Info about a droplet\n\n    $ tugboat info admin\n    Droplet fuzzy name provided. Finding droplet ID...done, 13231512 (pearkes-admin-001)\n\n    Name:             pearkes-admin-001\n    ID:               13231512\n    Status:           active\n    IP:               30.30.30.3\n    Backups Active:   false\n    IP6:              2A03:B0C0:0001:00D0:0000:0000:0308:D001\n    Region:           London 1 - lon1\n    Image:            6918990 - ubuntu-14-04-x64\n    Size:             1GB\n\nPrint info in machine-readable format. The ``--porcelain`` flag silences extra output for easy parsing. Fuzzy name matching is not supported with the ``--porcelain`` flag.\n\n    $ tugboat info -n pearkes-admin-001 --porcelain\n    name pearkes-admin-001\n    id 13231512\n    status active\n    ip4 30.30.30.3\n    region lon1\n    image 6918990\n    size 1gb\n    backups_active false\n\nPrint a single attribute.\n\n    $ tugboat info -n pearkes-admin-001 --attribute ip --porcelain\n    30.30.30.3\n\n\n### Destroy a droplet\n\n    $ tugboat destroy pearkes-www-002\n    Droplet fuzzy name provided. Finding droplet ID...done, 13231515 (pearkes-www-002)\n    Warning! Potentially destructive action. Please confirm [y/n]: y\n    Queuing destroy for 13231515 (pearkes-www-002)...done\n\n### Restart a droplet\n\n    $ tugboat restart admin\n    Droplet fuzzy name provided. Finding droplet ID...done, 13231512 (pearkes-admin-001)\n    Queuing restart for 13231512 (pearkes-admin-001)...done\n\n### Shutdown a droplet\n\n    $ tugboat halt admin\n    Droplet fuzzy name provided. Finding droplet ID...done, 13231512 (pearkes-admin-001)\n    Queuing shutdown for 13231512 (pearkes-admin-001)...done\n\n### Snapshot a droplet\n\n    $ tugboat snapshot test-admin-snaphot admin\n    Queuing snapshot 'test-admin-snapshot' for 13231512 (pearkes-admin-001)...done\n\n### Resize a droplet\n\n    $ tugboat resize admin -s 66\n    Queuing resize for 13231512 (pearkes-admin-001)...done\n\n### Enabling backups on a droplet\n\n    $ tugboat backup_config admin --on\n    Droplet fuzzy name provided. Finding droplet ID...done\\e[0m, 6918990 (example.com)\n    Backup action enable backups is complete\n\n### Disabling backups on a droplet\n\n    $ tugboat backup_config admin --off\n    Droplet fuzzy name provided. Finding droplet ID...done\\e[0m, 6918990 (example.com)\n    Backup action disable backups is complete\n\n### List Available Images\n\nYou can list all images\n\n    $ tugboat images\n    Showing both private and public images\n    Private Images:\n    My application image (id: 6376601, distro: Ubuntu)\n\n    Public Images:\n    745.1.0 (alpha) (slug: coreos-alpha, id: 12789325, distro: CoreOS)\n    723.3.0 (beta) (slug: coreos-beta, id: 12789350, distro: CoreOS)\n    717.3.0 (stable) (slug: coreos-stable, id: 12789351, distro: CoreOS)\n    ....\n\nOr just list images that you have created.\n\n    $ tugboat images --show_just_private_images # or -p\n    Showing just private images\n    Private Images:\n    My application image (id: 6376601, distro: Ubuntu)\n    ....\n\n### List Current Snapshots\n\n    $ tugboat snapshots\n    code-freeze-backup-october (id: 2013184, resource_type: droplet, created_at: 2016-10-06T11:43:06Z)\n    test-admin 2017-05-31 (id: 20234485, resource_type: droplet, created_at: 2017-05-31T02:07:07Z)\n    test-admin 2017-11-08 (id: 21133567, resource_type: droplet, created_at: 2017-11-08T02:49:09Z)\n    test-admin 2017-11-15 (id: 22355454, resource_type: droplet, created_at: 2017-11-15T03:11:08Z)\n    test-admin 2017-11-22 (id: 24523423, resource_type: droplet, created_at: 2017-11-22T03:10:09Z)\n    test-admin 2017-11-29 (id: 26212345, resource_type: droplet, created_at: 2017-11-29T03:15:25Z)\n    ....\n\n\n### List Available Sizes\n\n    $ tugboat sizes\n    Sizes:\n    Disk: 20GB, Memory: 512MB (slug: 512mb)\n    Disk: 30GB, Memory: 1024MB (slug: 1gb)\n    Disk: 40GB, Memory: 2048MB (slug: 2gb)\n    Disk: 60GB, Memory: 4096MB (slug: 4gb)\n    Disk: 80GB, Memory: 8192MB (slug: 8gb)\n    Disk: 160GB, Memory: 16384MB (slug: 16gb)\n    Disk: 320GB, Memory: 32768MB (slug: 32gb)\n    Disk: 480GB, Memory: 49152MB (slug: 48gb)\n    Disk: 640GB, Memory: 65536MB (slug: 64gb)\n    ...\n\n### List Available Regions\n\n    $ tugboat regions\n    Regions:\n    Amsterdam 1 (slug: ams1)\n    Amsterdam 2 (slug: ams2)\n    Amsterdam 3 (slug: ams3)\n    London 1 (slug: lon1)\n    New York 1 (slug: nyc1)\n    New York 2 (slug: nyc2)\n    New York 3 (slug: nyc3)\n    San Francisco 1 (slug: sfo1)\n    Singapore 1 (slug: sgp1)\n\n### Add SSH keys\n\n    $ tugboat add-key digitalocean\n    Possible public key paths from /Users/pearkes/.ssh:\n\n    /Users/pearkes/.ssh/digitalocean.pub\n    /Users/pearkes/.ssh/fog.pub\n    /Users/pearkes/.ssh/github.pub\n    /Users/pearkes/.ssh/id_rsa.pub\n    /Users/pearkes/.ssh/terraform.pub\n\n    Enter the path to your SSH key: /Users/petersouter/.ssh/digitalocean.pub\n    Queueing upload of SSH key 'digitalocean'...SSH Key uploaded\n\n    Name: digitalocean\n    ID: 1384812\n    ...\n\n### List SSH Keys\n\n    $ tugboat keys\n    Keys:\n    Name: pearkes, (id: 231192), fingerprint: 3b:16:bf:e4:8b:00:8b:b8:59:8c:a9:d3:f0:19:45:fa\n    ...\n\n### Wait for Droplet State\n\nSometimes you want to wait for a droplet to enter some state, for\nexample \"off\".\n\n    $ tugboat wait admin --state off\n    Droplet fuzzy name provided. Finding droplet ID...done, 13231512 (pearkes-admin-001)\n    Waiting for droplet to become off....\n    ...\n\nThis will simply block until the droplet returns a state of \"off\".\nA period will be printed after each request.\n\n## Help\n\nIf you're curious about command flags for a specific command, you can\nask tugboat about it.\n\n    $ tugboat help restart\n\n\nFor a complete overview of all of the available commands, run:\n\n    $ tugboat help\n\nDepending on your local configuration, you may need to install a CA bundle (OS X only) using [homebrew](http://brew.sh/) to communicate with DigitalOcean through SSL/TLS:\n\n    $ brew install curl-ca-bundle\n\nAfter installation, source the bundle path in your `.bash_profile`/`.bashrc`:\n\n    export SSL_CERT_FILE=/usr/local/opt/curl-ca-bundle/share/ca-bundle.crt\n\n## Reporting Bugs\n\nYes, please!\n\nYou can create a new issue [here](https://github.com/pearkes/tugboat/issues/new). To help with the investigation of your issue, you can set the environment variable DEBUG to give verbose Faraday logging.\n\n* DEBUG=1 is full unredacted\n* DEBUG=2 redacts private keys from the log.\n\nExample:\n\n```bash\nDEBUG=2 bundle exec tugboat regions\nI, [2015-12-06T12:04:27.148922 #92772]  INFO -- : Started GET request to: https://api.digitalocean.com/v2/regions?per_page=200\nD, [2015-12-06T12:04:27.149334 #92772] DEBUG -- : Request Headers:\n----------------\nAuthorization : Bearer [TOKEN REDACTED]\nContent-Type  : application/json\nUser-Agent    : Faraday v0.9.2\n\nRequest Body:\n-------------\n{\n  \"regions\": [\n    {\n      \"name\": \"New York 1\",\n      \"slug\": \"nyc1\",\n      \"sizes\": [\n        \"32gb\",\n        \"16gb\",\n        \"2gb\",\n        \"1gb\",\n        \"4gb\",\n        \"8gb\",\n        \"512mb\",\n        \"64gb\",\n        \"48gb\"\n      ],\n      \"features\": [\n        \"private_networking\",\n        \"backups\",\n        \"ipv6\",\n        \"metadata\"\n      ],\n      \"available\": true\n    },\n    {\n      \"name\": \"Amsterdam 1\",\n      \"slug\": \"ams1\",\n      \"sizes\": [\n        \"16gb\",\n        \"2gb\",\n        \"1gb\",\n        \"4gb\",\n        \"8gb\",\n        \"512mb\"\n      ],\n      \"features\": [\n        \"backups\"\n      ],\n      \"available\": true\n    },\n    {\n      \"name\": \"San Francisco 1\",\n      \"slug\": \"sfo1\",\n      \"sizes\": [\n        \"32gb\",\n        \"16gb\",\n        \"2gb\",\n        \"1gb\",\n        \"4gb\",\n        \"8gb\",\n        \"512mb\",\n        \"64gb\",\n        \"48gb\"\n      ],\n      \"features\": [\n        \"private_networking\",\n        \"backups\",\n        \"ipv6\",\n        \"metadata\"\n      ],\n      \"available\": true\n    },\n    {\n      \"name\": \"New York 2\",\n      \"slug\": \"nyc2\",\n      \"sizes\": [\n        \"32gb\",\n        \"16gb\",\n        \"2gb\",\n        \"1gb\",\n        \"4gb\",\n        \"8gb\",\n        \"512mb\",\n        \"64gb\",\n        \"48gb\"\n      ],\n      \"features\": [\n        \"private_networking\",\n        \"backups\",\n        \"ipv6\",\n        \"metadata\"\n      ],\n      \"available\": true\n    },\n    {\n      \"name\": \"Amsterdam 2\",\n      \"slug\": \"ams2\",\n      \"sizes\": [\n        \"32gb\",\n        \"16gb\",\n        \"2gb\",\n        \"1gb\",\n        \"4gb\",\n        \"8gb\",\n        \"512mb\",\n        \"64gb\",\n        \"48gb\"\n      ],\n      \"features\": [\n        \"private_networking\",\n        \"backups\",\n        \"ipv6\",\n        \"metadata\"\n      ],\n      \"available\": true\n    },\n    {\n      \"name\": \"Singapore 1\",\n      \"slug\": \"sgp1\",\n      \"sizes\": [\n        \"32gb\",\n        \"16gb\",\n        \"2gb\",\n        \"1gb\",\n        \"4gb\",\n        \"8gb\",\n        \"512mb\",\n        \"64gb\",\n        \"48gb\"\n      ],\n      \"features\": [\n        \"private_networking\",\n        \"backups\",\n        \"ipv6\",\n        \"metadata\"\n      ],\n      \"available\": true\n    },\n    {\n      \"name\": \"London 1\",\n      \"slug\": \"lon1\",\n      \"sizes\": [\n        \"32gb\",\n        \"16gb\",\n        \"2gb\",\n        \"1gb\",\n        \"4gb\",\n        \"8gb\",\n        \"512mb\",\n        \"64gb\",\n        \"48gb\"\n      ],\n      \"features\": [\n        \"private_networking\",\n        \"backups\",\n        \"ipv6\",\n        \"metadata\"\n      ],\n      \"available\": true\n    },\n    {\n      \"name\": \"New York 3\",\n      \"slug\": \"nyc3\",\n      \"sizes\": [\n        \"32gb\",\n        \"16gb\",\n        \"2gb\",\n        \"1gb\",\n        \"4gb\",\n        \"8gb\",\n        \"512mb\",\n        \"64gb\",\n        \"48gb\"\n      ],\n      \"features\": [\n        \"private_networking\",\n        \"backups\",\n        \"ipv6\",\n        \"metadata\"\n      ],\n      \"available\": true\n    },\n    {\n      \"name\": \"Amsterdam 3\",\n      \"slug\": \"ams3\",\n      \"sizes\": [\n        \"32gb\",\n        \"16gb\",\n        \"2gb\",\n        \"1gb\",\n        \"4gb\",\n        \"8gb\",\n        \"512mb\",\n        \"64gb\",\n        \"48gb\"\n      ],\n      \"features\": [\n        \"private_networking\",\n        \"backups\",\n        \"ipv6\",\n        \"metadata\"\n      ],\n      \"available\": true\n    },\n    {\n      \"name\": \"Frankfurt 1\",\n      \"slug\": \"fra1\",\n      \"sizes\": [\n        \"32gb\",\n        \"16gb\",\n        \"2gb\",\n        \"1gb\",\n        \"4gb\",\n        \"8gb\",\n        \"512mb\",\n        \"64gb\",\n        \"48gb\"\n      ],\n      \"features\": [\n        \"private_networking\",\n        \"backups\",\n        \"ipv6\",\n        \"metadata\"\n      ],\n      \"available\": true\n    },\n    {\n      \"name\": \"Toronto 1\",\n      \"slug\": \"tor1\",\n      \"sizes\": [\n        \"32gb\",\n        \"16gb\",\n        \"2gb\",\n        \"1gb\",\n        \"4gb\",\n        \"8gb\",\n        \"512mb\",\n        \"64gb\",\n        \"48gb\"\n      ],\n      \"features\": [\n        \"private_networking\",\n        \"backups\",\n        \"ipv6\",\n        \"metadata\"\n      ],\n      \"available\": true\n    }\n  ],\n  \"links\": {\n  },\n  \"meta\": {\n    \"total\": 11\n  }\n}\n```\n\n## Contributing\n\nSee the [contributing guide](CONTRIBUTING.md).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpetems%2Ftugboat","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpetems%2Ftugboat","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpetems%2Ftugboat/lists"}