Files
homelab-optimized/docs/admin/PORTAINER_API_GUIDE.md
Gitea Mirror Bot 7af757f303
Some checks failed
Documentation / Build Docusaurus (push) Failing after 5m9s
Documentation / Deploy to GitHub Pages (push) Has been skipped
Sanitized mirror from private repository - 2026-04-01 03:42:17 UTC
2026-04-01 03:42:17 +00:00

309 lines
9.6 KiB
Markdown

# 🐳 Portainer API Management Guide
*Complete guide for managing homelab infrastructure via Portainer API*
## 📋 Overview
This guide covers how to interact with the Portainer API for managing the homelab infrastructure, including GitOps deployments, container management, and system monitoring.
## 🔗 API Access Information
### Primary Portainer Instance
- **URL**: https://192.168.0.200:9443
- **API Endpoint**: https://192.168.0.200:9443/api
- **Version**: 2.39.0 (Portainer Enterprise Edition)
- **Instance ID**: dc043e05-f486-476e-ada3-d19aaea0037d
### Authentication
Portainer supports two authentication methods:
**Option A — API Access Token (recommended):**
```bash
# Tokens starting with ptr_ use the X-API-Key header (NOT Bearer)
export PORTAINER_TOKEN="<your-portainer-api-token>"
curl -k -H "X-API-Key: $PORTAINER_TOKEN" https://192.168.0.200:9443/api/stacks
```
**Option B — JWT (username/password):**
```bash
TOKEN=$(curl -k -s -X POST https://192.168.0.200:9443/api/auth \
-H "Content-Type: application/json" \
-d '{"Username":"admin","Password":"YOUR_PASSWORD"}' | jq -r '.jwt')
curl -k -H "Authorization: Bearer $TOKEN" https://192.168.0.200:9443/api/stacks
```
> **Note:** `ptr_` API tokens must use `X-API-Key`, not `Authorization: Bearer`.
> Using `Bearer` with a `ptr_` token returns `{"message":"Invalid JWT token"}`.
### Endpoint IDs
| Endpoint | ID |
|---|---|
| Atlantis | 2 |
| Calypso | 443397 |
| Concord NUC | 443398 |
| Homelab VM | 443399 |
| RPi5 | 443395 |
## 🚀 GitOps Management
### Check GitOps Stack Status
```bash
# List all stacks with Git config
curl -k -s -H "X-API-Key: $PORTAINER_TOKEN" \
https://192.168.0.200:9443/api/stacks | \
jq '[.[] | select(.GitConfig.URL) | {id:.Id, name:.Name, status:.Status, file:.GitConfig.ConfigFilePath, credId:.GitConfig.Authentication.GitCredentialID}]'
# Get specific stack details
curl -k -H "X-API-Key: $PORTAINER_TOKEN" \
https://192.168.0.200:9443/api/stacks/{stack_id}
```
### Trigger GitOps Deployment
```bash
# Redeploy stack from Git (pass creds inline to bypass saved credential cache)
curl -k -X PUT -H "X-API-Key: $PORTAINER_TOKEN" \
-H "Content-Type: application/json" \
"https://192.168.0.200:9443/api/stacks/{stack_id}/git/redeploy?endpointId={endpoint_id}" \
-d '{"pullImage":true,"prune":false,"repositoryAuthentication":true,"repositoryUsername":"vish","repositoryPassword":"YOUR_GITEA_TOKEN"}'
```
### Manage Git Credentials
```bash
# The saved Git credential used by most stacks is "portainer-homelab" (credId: 1)
# List saved credentials:
curl -k -s -H "X-API-Key: $PORTAINER_TOKEN" \
https://192.168.0.200:9443/api/users/1/gitcredentials | jq '.'
# Update the saved credential (e.g. after rotating the Gitea token):
curl -k -s -X PUT \
-H "X-API-Key: $PORTAINER_TOKEN" \
-H "Content-Type: application/json" \
"https://192.168.0.200:9443/api/users/1/gitcredentials/1" \
-d '{"name":"portainer-homelab","username":"vish","password":"YOUR_NEW_GITEA_TOKEN"}'
```
### Scan Containers for Broken Credentials
```bash
# Useful after a sanitization commit — finds any REDACTED values in running container envs
python3 << 'EOF'
import json, urllib.request, ssl
ctx = ssl.create_default_context(); ctx.check_hostname = False; ctx.verify_mode = ssl.CERT_NONE
token = "REDACTED_TOKEN"
base = "https://192.168.0.200:9443/api"
endpoints = {"atlantis":2,"calypso":443397,"nuc":443398,"homelab":443399,"rpi5":443395}
def api(p):
req = urllib.request.Request(f"{base}{p}", headers={"X-API-Key": token})
with urllib.request.urlopen(req, context=ctx) as r: return json.loads(r.read())
for ep_name, ep_id in endpoints.items():
for c in api(f"/endpoints/{ep_id}/docker/containers/json?all=true"):
info = api(f"/endpoints/{ep_id}/docker/containers/{c['Id'][:12]}/json")
hits = [e for e in (info.get("Config",{}).get("Env") or []) if "REDACTED" in e]
if hits: print(f"[{ep_name}] {c['Names'][0]}"); [print(f" {h}") for h in hits]
EOF
```
## 📊 Container Management
### List All Containers
```bash
# Get all containers across all endpoints
curl -k -H "Authorization: Bearer $PORTAINER_TOKEN" \
https://192.168.0.200:9443/api/endpoints/1/docker/containers/json?all=true
```
### Container Health Checks
```bash
# Check container status
curl -k -H "Authorization: Bearer $PORTAINER_TOKEN" \
https://192.168.0.200:9443/api/endpoints/1/docker/containers/{container_id}/json | \
jq '.State.Health.Status'
# Get container logs
curl -k -H "Authorization: Bearer $PORTAINER_TOKEN" \
https://192.168.0.200:9443/api/endpoints/1/docker/containers/{container_id}/logs?stdout=1&stderr=1&tail=100
```
## 🖥️ System Information
### Endpoint Status
```bash
# List all endpoints (servers)
curl -k -H "Authorization: Bearer $PORTAINER_TOKEN" \
https://192.168.0.200:9443/api/endpoints
# Get system information
curl -k -H "Authorization: Bearer $PORTAINER_TOKEN" \
https://192.168.0.200:9443/api/endpoints/1/docker/system/info
```
### Resource Usage
```bash
# Get system stats
curl -k -H "Authorization: Bearer $PORTAINER_TOKEN" \
https://192.168.0.200:9443/api/endpoints/1/docker/system/df
# Container resource usage
curl -k -H "Authorization: Bearer $PORTAINER_TOKEN" \
https://192.168.0.200:9443/api/endpoints/1/docker/containers/{container_id}/stats?stream=false
```
## 🔧 Automation Scripts
### Health Check Script
```bash
#!/bin/bash
# portainer-health-check.sh
PORTAINER_URL="https://192.168.0.200:9443"
TOKEN="$PORTAINER_TOKEN"
echo "🔍 Checking Portainer API status..."
STATUS=$(curl -k -s "$PORTAINER_URL/api/status" | jq -r '.Version')
echo "✅ Portainer Version: $STATUS"
echo "🐳 Checking container health..."
CONTAINERS=$(curl -k -s -H "Authorization: Bearer $TOKEN" \
"$PORTAINER_URL/api/endpoints/1/docker/containers/json" | \
jq -r '.[] | select(.State=="running") | .Names[0]' | wc -l)
echo "✅ Running containers: $CONTAINERS"
echo "📊 Checking GitOps stacks..."
STACKS=$(curl -k -s -H "Authorization: Bearer $TOKEN" \
"$PORTAINER_URL/api/stacks" | \
jq -r '.[] | select(.Status==1) | .Name' | wc -l)
echo "✅ Active stacks: $STACKS"
```
### GitOps Deployment Script
```bash
#!/bin/bash
# deploy-stack.sh
STACK_NAME="$1"
PORTAINER_URL="https://192.168.0.200:9443"
TOKEN="$PORTAINER_TOKEN"
if [[ -z "$STACK_NAME" ]]; then
echo "Usage: $0 <stack_name>"
exit 1
fi
echo "🚀 Deploying stack: $STACK_NAME"
# Find stack ID
STACK_ID=$(curl -k -s -H "Authorization: Bearer $TOKEN" \
"$PORTAINER_URL/api/stacks" | \
jq -r ".[] | select(.Name==\"$STACK_NAME\") | .Id")
if [[ -z "$STACK_ID" ]]; then
echo "❌ Stack not found: $STACK_NAME"
exit 1
fi
# Trigger redeploy
curl -k -X PUT -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
"$PORTAINER_URL/api/stacks/$STACK_ID/git/redeploy" \
-d '{"RepositREDACTED_APP_PASSWORD":"main","PullImage":true}'
echo "✅ Deployment triggered for stack: $STACK_NAME"
```
## 📈 Monitoring Integration
### Prometheus Metrics
```bash
# Get Portainer metrics (if enabled)
curl -k -H "Authorization: Bearer $PORTAINER_TOKEN" \
https://192.168.0.200:9443/api/endpoints/1/docker/containers/json | \
jq '[.[] | {name: .Names[0], state: .State, status: .Status}]'
```
### Alerting Integration
```bash
# Check for unhealthy containers
UNHEALTHY=$(curl -k -s -H "Authorization: Bearer $PORTAINER_TOKEN" \
https://192.168.0.200:9443/api/endpoints/1/docker/containers/json | \
jq -r '.[] | select(.State != "running") | .Names[0]')
if [[ -n "$UNHEALTHY" ]]; then
echo "⚠️ Unhealthy containers detected:"
echo "$UNHEALTHY"
fi
```
## 🔐 Security Best Practices
### API Token Management
- **Rotation**: Rotate API tokens regularly (monthly)
- **Scope**: Use least-privilege tokens when possible
- **Storage**: Store tokens securely (environment variables, secrets management)
### Network Security
- **TLS**: Always use HTTPS endpoints
- **Firewall**: Restrict API access to authorized networks
- **Monitoring**: Log all API access for security auditing
## 🚨 Troubleshooting
### Common Issues
#### Authentication Failures
```bash
# Check token validity
curl -k -H "Authorization: Bearer $PORTAINER_TOKEN" \
https://192.168.0.200:9443/api/users/me
```
#### Connection Issues
```bash
# Test basic connectivity
curl -k -s https://192.168.0.200:9443/api/status
# Check certificate issues
openssl s_client -connect 192.168.0.200:9443 -servername atlantis.vish.local
```
#### GitOps Sync Issues
```bash
# Check stack deployment logs
curl -k -H "Authorization: Bearer $PORTAINER_TOKEN" \
https://192.168.0.200:9443/api/stacks/{stack_id}/logs
```
## 📚 API Documentation
### Official Resources
- **Portainer API Docs**: https://docs.portainer.io/api/
- **Swagger UI**: https://192.168.0.200:9443/api/docs/
- **API Reference**: Available in Portainer web interface
### Useful Endpoints
- `/api/status` - System status
- `/api/endpoints` - Managed environments
- `/api/stacks` - GitOps stacks
- `/api/containers` - Container management
- `/api/images` - Image management
- `/api/volumes` - Volume management
- `/api/networks` - Network management
## 🔄 Integration with Homelab
### GitOps Workflow
1. **Code Change**: Update compose files in Git repository
2. **Webhook**: Git webhook triggers Portainer sync (optional)
3. **Deployment**: Portainer pulls changes and redeploys
4. **Verification**: API checks confirm successful deployment
### Monitoring Integration
- **Health Checks**: Regular API calls to verify system health
- **Metrics Collection**: Export container metrics to Prometheus
- **Alerting**: Trigger alerts on deployment failures or container issues
---
**Last Updated**: February 14, 2026
**Portainer Version**: 2.33.7
**API Version**: Compatible with Portainer EE
**Status**: ✅ Active and Operational