- Help text showed wrong config path (~/.portainer-cli vs ~/.config/portainer-cli)
- --port without colon (e.g. --port 8080) crashed with nil/tcp key; now errors clearly
- --cmd used naive split(' ') breaking quoted args; switched to Shellwords.split
- --env without '=' (e.g. --env FOO) silently passed empty value; now errors clearly
- SSL/connection errors surfaced as raw exception; now caught with actionable message
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
portainer-cli
A Ruby command-line tool for interacting with Portainer via its REST API. List environments, stacks, containers, volumes and networks — and open fully interactive shells inside running containers directly from your terminal.
This tool was fully generated by AI (Claude, by Anthropic) through an iterative conversation-driven development session.
Features
- List endpoints, stacks, containers, volumes, and networks
- Create stacks (from file or inline compose) and containers
- Interactive exec into containers via WebSocket — works like
docker exec -itbut through Portainer - Smart container name resolution: fuzzy matching using Docker Compose naming conventions (
<stack>-<service>-<N>) - Automatic endpoint resolution — no need to look up endpoint IDs manually
- Supports both API key and JWT token authentication
- Configurable SSL verification (useful for self-signed certificates)
--run CMDflag for running a specific command (e.g.rails c)--quietflag for scripting and AI agent use cases
Requirements
- Ruby 3.x
websocketgem- A running Portainer instance (v2.x or later)
Installation
git clone https://github.com/grzlus/portainer-cli
cd portainer-cli
bundle install
chmod +x bin/portainer-cli
# Link into your PATH (adjust the target to wherever suits you)
ln -sf "$PWD/bin/portainer-cli" ~/bin/portainer-cli
Configuration
portainer-cli configure
You will be prompted for:
- Portainer URL — e.g.
https://portainer.example.com - Authentication — API key (recommended, no expiry) or JWT token
- SSL verification — answer
nif your instance uses a self-signed certificate
Configuration is saved to ~/.config/portainer-cli/config.yml (mode 0600).
Manual config
# ~/.config/portainer-cli/config.yml
url: https://portainer.example.com
api_key: ptr_xxxxxxxxxxxxxxxxxxxxxxxxxxxx
ssl_verify: true
Usage
List resources
portainer-cli list endpoints
portainer-cli list stacks
portainer-cli list containers <endpoint-id>
portainer-cli list volumes <endpoint-id>
portainer-cli list networks <endpoint-id>
Open an interactive shell
# Resolves endpoint automatically from the stack name.
# Container name defaults to the stack name, then falls back to 'app'.
portainer-cli console <stack>
portainer-cli console <stack> <container>
# Examples
portainer-cli console myapp
portainer-cli console myapp worker
portainer-cli console myapp --shell /bin/bash
Run a specific command
portainer-cli console myapp --run "rails c"
portainer-cli console myapp --run "bundle exec rake db:migrate"
Quiet mode (scripting / AI agents)
Suppresses all status output — only the container's own stdout/stderr is printed.
portainer-cli console myapp --quiet --run "rails runner 'puts User.count'"
Create resources
# Stack from a compose file
portainer-cli create stack --endpoint 1 --name myapp --file docker-compose.yml
# Stack from inline compose
portainer-cli create stack --endpoint 1 --name myapp --compose "version: '3'
services:
web:
image: nginx"
# Container
portainer-cli create container --endpoint 1 --image nginx:alpine --name web \
--port 8080:80 --env APP_ENV=production
Low-level exec (manual endpoint ID)
portainer-cli exec <endpoint-id> <container-name-or-id>
portainer-cli exec <endpoint-id> <container-name-or-id> --shell /bin/bash
Container name resolution
When using console, names are resolved in this order:
- Exact match — full container name or ID prefix
- Compose pattern —
<stack>-<service>-<N>(e.g.librarian→librarian-librarian-1) - Substring match — scoped to the stack's own containers
appfallback — tries<stack>-app-1as a last resort
If multiple containers match ambiguously, a list is printed and the command exits.
Debugging
portainer-cli --debug console myapp
Prints the WebSocket URL, auth headers, and the full HTTP upgrade handshake request/response — useful for diagnosing connection issues behind reverse proxies.
License
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
See LICENSE for the full text.